home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / GrowBoxDock / Sources / GXFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-30  |  97.9 KB  |  3,311 lines

  1. /*
  2.     File:        GXFile.c
  3.  
  4.     Contains:    GX print file support for simple text application.
  5.  
  6.     Version:    SimpleText 1.4 or later
  7.  
  8.     Written by:    Tom Dowdy
  9.                 DAL = Dave Lyons
  10.  
  11.     Copyright:    © 1993-1997 by Apple Computer, Inc., all rights reserved.
  12.  
  13.     File Ownership:
  14.  
  15.         DRI:                Tom Dowdy
  16.  
  17.         Other Contact:        Jim Negrette
  18.  
  19.         Technology:            Macintosh Graphics Group
  20.  
  21.     Writers:
  22.  
  23.         (ecs)    Eric Schlegel
  24.         (dmp)    Dave Polaschek
  25.         (ted)    Tom Dowdy
  26.         (TD)    Tom Dowdy
  27.  
  28.     Change History (most recent first):
  29.  
  30.     $Log: GXFile.c,v $
  31.     Revision 1.8  2000/07/01 02:23:49  mig
  32.     some fixes for framework-style includes
  33.     
  34.     Revision 1.7  1999/05/26 17:03:12  wilkes
  35.     Removed all vestiges of Zones...
  36.     
  37.     Revision 1.6  1999/05/20 22:41:21  christ
  38.     CountMItems -> CountMenuItems
  39.     
  40.     Revision 1.5  1998/10/12 18:50:52  danp
  41.     *** empty log message ***
  42.     
  43.     Revision 1.4  1998/09/15 18:59:43  jiarocci
  44.     SimpleText now builds with -DTARGET_CARBON=1. Still needs further cleanup.
  45.     
  46.     Revision 1.3  1998/03/30 22:12:26  mkellner
  47.     Update to use new GetQDxxxx macros for qd.globals
  48.  
  49.     Revision 1.2  1998/03/20 03:19:54  mkellner
  50.     change qd.thePort to FrontWindow()
  51.     add SysEnvirons
  52.     
  53.     Revision 1.1.1.1  1998/03/18 22:56:09  ivory
  54.     Initial checkin of SimpleText.
  55.     
  56.         
  57.         5     8/20/97 4:23 PM Tom Dowdy
  58.         1674136: adjust cursor after select all
  59.         
  60.         4     8/11/97 3:05 PM Tom Dowdy
  61.         rolling in nav services
  62.         
  63.         3     7/29/97 2:07 PM Tom Dowdy
  64.         Removed all of the old and boring refs
  65.         
  66.         2     7/29/97 1:52 PM Tom Dowdy
  67.         Various new interface fixes
  68.         
  69.         1     7/28/97 11:18 AM Duane Byram
  70.         first added to Source Safe project
  71.  
  72.         <19>     6/17/97    ted        Getting rid of some compiler warnings
  73.         <18>     5/14/97    ted        More drag clipping bug fixes
  74.         <17>     5/14/97    ted        More drag clipping bug fixes
  75.         <16>    11/26/96    ecs        support GXGraphics extension; smarter cursor adjustment
  76.         <15>      9/9/96    dmp        staticfy local functions to eliminate warnings in MWC.
  77.         <14>      7/9/96    ted        adding pragma unused
  78.         <13>     5/31/96    ted        AddImage -> SetImage
  79.         <12>     5/31/96    ted        adding PPC, FAT, and NuKernel builds
  80.         <11>     4/11/96    ted        cwindowptr->windowptr
  81.         <10>      2/8/96    ted        CountMenuItems->CountMItems (??)
  82.          <9>     1/12/96    ted        need to cull style and ink also
  83.          <8>     1/12/96    ted        dealing with override transforms on cullshape
  84.          <7>     11/2/95    ted        BlockMoveData
  85.          <6>     10/5/95    ted        fixing hilight for rotated shapes
  86.          <5>     10/2/95    TD        adding in other selections for editing
  87.          <4>     9/11/95    TD        fixing zoom in icons
  88.          <3>      9/8/95    TD        started annotation
  89.          <2>     8/22/95    TD        moving enum to simpletext.h
  90.          <1>     8/21/95    TD        First checked in.
  91.         <20>     12/8/94    DAL        Radar #1204706. Now handles updates behind the go-to-page
  92.                                     dialog.
  93.  
  94. */
  95.  
  96. #include "MacIncludes.h"
  97.  
  98. #include "GXFile.h"
  99.  
  100. #pragma segment GXFile
  101.  
  102. // --------------------------------------------------------------------------------------------------------------
  103. // PRIVATE TYPEDEFS AND DECLARES
  104. // --------------------------------------------------------------------------------------------------------------
  105. // items to the left of the horizontal scroll bar
  106. #define kScrollAreaWidth    120
  107. #define kPageControlsWidth    32
  108. #define kZoomControlsWidth    26
  109. #define kToolControlWidth    16
  110.  
  111. // items in the pop up page selection window
  112. #define kPageSliderHeight    10
  113. #define kPageSliderMargins    7
  114. #define kPageThumbEdge        4
  115. #define kPageThumbHeight    (kPageSliderHeight + kPageThumbEdge*2)
  116. #define kPageThumbWidth        (kPageThumbHeight / 2)
  117. #define kPageThumbMargins    3
  118. #define kProxyHeight        150
  119. #define kProxyWidth            150
  120. #define kPopUpWindowHeightSmall    (kPageThumbHeight + kPageSliderMargins*2 + kPageThumbEdge*2)
  121. #define kPopUpWindowHeightLarge    (kPageThumbHeight + kPageSliderMargins*3 + kPageThumbEdge*2 + kProxyHeight)
  122.  
  123. #define kMinGXDocSize        kMinDocSize
  124.  
  125. // PICT proxies for the pages
  126. #define kProxyBaseID        (gxPrintingTagID)
  127. #define kProxyType            'prxy'
  128.  
  129. // flattened GX shapes for annotations
  130. #define kAnnotationBaseID    (gxPrintingTagID)
  131. #define kAnnotationType        'anot'
  132.  
  133. // table of pop up menu items and corosponding zoom factors
  134. typedef struct
  135.     {
  136.     short    menuItem;
  137.     Fixed    zoomFactor;
  138.     } ZoomTableEntry;
  139.     
  140. typedef struct
  141.     {
  142.     short    theFont;
  143.     short    theSize;
  144.     } TextState;
  145.     
  146. typedef struct  
  147.     {
  148.     gxSpoolBlock    spool;
  149.     long            reference;
  150.     long            position;
  151.     long            size;
  152.     void            *data;
  153.     void            *userField;
  154.     } userSpool;
  155.  
  156. #define LONGALIGN(n)        (((n) + 3) & ~3L)
  157. #define kAtomHeaderSize        (sizeof(Size) + sizeof(OSType))
  158. #define ABS(n)                (((n) < 0) ? -(n) : (n))
  159.  
  160. #if GENERATINGCFM
  161.     extern pascal OSErr SetImageDescriptionExtension(ImageDescriptionHandle desc, Handle extension, long idType);
  162. #endif
  163.  
  164. // --------------------------------------------------------------------------------------------------------------
  165. // FORWARD DECLARES
  166. // --------------------------------------------------------------------------------------------------------------
  167. OSErr    GXGetDocumentRect(WindowPtr pWindow, WindowDataPtr pData, 
  168.             LongRect * documentRectangle, Boolean forGrow);
  169. OSErr    GXCommand(WindowPtr pWindow, WindowDataPtr pData, short commandID, long menuResult);
  170.  
  171. // --------------------------------------------------------------------------------------------------------------
  172. // LOCAL GLOBALS
  173. // --------------------------------------------------------------------------------------------------------------
  174. static ZoomTableEntry gZoomTable[] = {
  175.                                 {i50,     0x8000},
  176.                                 {i100,    ff(1)},
  177.                                 {i112,    0x00011EB8},
  178.                                 {i150,     0x00018000},
  179.                                 {i200,    ff(2)},
  180.                                 {i400,    ff(4)},
  181.                                 {0,0}};
  182.  
  183.  
  184. // --------------------------------------------------------------------------------------------------------------
  185. // PRIVATE ROUTINES
  186. // --------------------------------------------------------------------------------------------------------------
  187.  
  188. static void GetCurrentPageAndPaper(WindowDataPtr pData, gxRectangle *pPageSize, gxRectangle *pPaperSize)
  189. {
  190.     GXGetFormatDimensions( ((GXDataPtr)pData)->currentPageFormat, pPageSize, pPaperSize);    
  191.     if (((GXDataPtr)pData)->dontShowMargins)
  192.         *pPaperSize = *pPageSize;
  193.         
  194. } // GetCurrentPageAndPaper
  195.  
  196. // ------------------------------------------------------------------------------------------------------
  197. static void InitColorMatrix(Fixed m[5][4])
  198. {
  199.     register Fixed *x;
  200.     register short i;
  201.  
  202.     x = &m[0][0];
  203.     for(i = 19; i>=0; i--)
  204.         *x++ = 0;
  205.     m[0][0] = m[1][1] = m[2][2] = m[3][3] = fixed1;           /* Identity matrix, for cleanliness */
  206.     
  207. } // InitColorMatrix
  208.  
  209. // --------------------------------------------------------------------------------------------------------------
  210. static void RectangleToRect(const gxRectangle* gxr, Rect* qdr)
  211. {
  212.     qdr->left = FixedRound(gxr->left);
  213.     qdr->top = FixedRound(gxr->top);
  214.     qdr->right = FixedRound(gxr->right);
  215.     qdr->bottom = FixedRound(gxr->bottom);
  216.     
  217. } // RectangleToRect
  218.  
  219. // --------------------------------------------------------------------------------------------------------------
  220. #define allocationIncrement   1024     /* the storage handle is grown by this amount */
  221.  
  222. static long HandleSpoolProc(gxSpoolCommand command,  userSpool *block)
  223. {
  224.     gxGraphicsError    anErr = noErr;
  225.     
  226.        switch (command)
  227.            {
  228.           case gxOpenReadSpool:
  229.              block->size = 0;
  230.              block->position = 0;
  231.               break;
  232.       
  233.           case gxOpenWriteSpool:
  234.              block->data = NewHandle(allocationIncrement);
  235.              block->size = allocationIncrement;
  236.              block->position = 0;
  237.             anErr = MemError();
  238.               break;
  239.       
  240.           case gxReadSpool:
  241.              BlockMoveData((*(char **) block->data) + block->position, block->spool.buffer, block->spool.count);
  242.              block->position += block->spool.count;
  243.               break;
  244.  
  245.           case gxWriteSpool:
  246.               {  
  247.             register long oldPosition;
  248.  
  249.             oldPosition = block->position;
  250.             block->position += block->spool.count;
  251.  
  252.             /* make sure there is at least enough room for one buffer size past current pointer */
  253.             if (block->position + block->spool.bufferSize > block->size)      
  254.                  {
  255.                 block->size += block->spool.bufferSize;
  256.                 HUnlock((Handle) block->data);
  257.                 SetHandleSize((Handle) block->data, block->size);
  258.                 anErr = MemError();
  259.                 HLock((Handle) block->data);
  260.                  }
  261.             if (anErr == noErr)
  262.                  BlockMoveData(block->spool.buffer, (*(char **) block->data + oldPosition), block->spool.count);
  263.               }
  264.               break;
  265.       
  266.           case gxCloseSpool:
  267.              SetHandleSize((Handle) block->data, block->position);
  268.               break;
  269.            }
  270.         
  271.    return anErr;
  272.    
  273. } // HandleSpoolProc
  274.  
  275. #if GENERATINGCFM
  276.     static RoutineDescriptor gHandleSpoolProcRD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, HandleSpoolProc);
  277.     static gxSpoolUPP gHandleSpoolProc = &gHandleSpoolProcRD;
  278. #else
  279.     static gxSpoolUPP gHandleSpoolProc = NewgxSpoolProc(HandleSpoolProc);
  280. #endif
  281.  
  282. // --------------------------------------------------------------------------------------------------------------
  283. static long* AppendAtom(long stream[], Size size, OSType tag, const void* data)
  284. {
  285.  
  286.     *stream++    = size + kAtomHeaderSize;
  287.     *stream++    = tag;
  288.     BlockMoveData(data, (Ptr)stream, size);
  289.  
  290.     return (long*)((char*)stream + size);
  291.     
  292. } // AppendAtom
  293.  
  294. // --------------------------------------------------------------------------------------------------------------
  295. static Handle CreateQDGXStream(gxShape source, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  296. /*
  297.  *    See the comment on DecompressShape for an explaination of the parameters.
  298.  *    This routine is used by both DecompressShape for embedding shapes in PICTs,
  299.  *    and AddQDGXRecorderFrame for making gx movies.
  300. */
  301. {
  302.     #define            gxForPrintingOnlyAtom    'fpto'
  303.     #define            gxEraseBackgroundAtom    'erbg'
  304.  
  305.     long            atomCount, shapeSize, proxieSize, dataSize, fontListSize;
  306.     Handle            dataHdl, shapeHdl;
  307.     gxFlatFontList*    fontList;
  308.     gxTag            fontListTag;
  309.       userSpool         block;
  310.  
  311.     block.spool.spoolProcedure = gHandleSpoolProc;
  312.     block.spool.buffer = nil;
  313.     block.spool.bufferSize = 0;
  314.     GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  315.     shapeHdl = (Handle) block.data;
  316.     if (shapeHdl == nil)
  317.         return nil;
  318.  
  319.     if (proxie)
  320.         {    
  321.         atomCount = 2;
  322.         proxieSize = LONGALIGN(GetHandleSize((Handle)proxie));
  323.         }
  324.     else
  325.         {    
  326.         atomCount = 1;
  327.         proxieSize = 0;
  328.         }
  329.     shapeSize = LONGALIGN(GetHandleSize(shapeHdl));
  330.  
  331.     if (forPrintingOnly)
  332.         ++atomCount;
  333.     if (eraseBackground)
  334.         ++atomCount;
  335.  
  336.     fontListSize = 0;
  337.     fontList = nil;
  338.     GXIgnoreGraphicsWarning(count_out_of_range);
  339.     if (GXGetShapeTags(source, gxFlatFontListItemTag, 1, 1, &fontListTag) > 0)
  340.         {    
  341.         fontListSize = GXGetTag(fontListTag, nil, nil);
  342.         if (fontListSize > 0)
  343.             {    
  344.             fontList = (gxFlatFontList*)NewPtr(fontListSize);
  345.             if (fontList != nil)
  346.                 {    
  347.                 GXGetTag(fontListTag, nil, fontList);
  348.                 fontListSize = LONGALIGN(fontListSize);
  349.                 ++atomCount;
  350.                 }
  351.             else
  352.                 fontListSize = 0;
  353.             }
  354.         }
  355.     GXPopGraphicsWarning();        // count_out_of_range
  356.  
  357.     dataSize = atomCount * kAtomHeaderSize + shapeSize + proxieSize + fontListSize + sizeof(long);
  358.     dataHdl = NewHandle(dataSize);
  359.     if (dataHdl == nil)
  360.         {    
  361.         DisposeHandle(shapeHdl);
  362.         if (fontList)
  363.             DisposePtr((Ptr)fontList);
  364.         return nil;
  365.         }
  366.     
  367.     {    
  368.         long* p = (long*)*dataHdl;
  369.  
  370.         if (forPrintingOnly)
  371.             p = AppendAtom(p, 0, gxForPrintingOnlyAtom, nil);
  372.         if (eraseBackground)
  373.             p = AppendAtom(p, 0, gxEraseBackgroundAtom, nil);
  374.         if (proxie)
  375.             p = AppendAtom(p, proxieSize, 'PICT', *proxie);
  376.         if (fontList)
  377.             p = AppendAtom(p, fontListSize, gxFlatFontListItemTag, fontList);
  378.         p = AppendAtom(p, shapeSize, 'qdgx', *shapeHdl);
  379.         *p++ = 0;        // end of the atom-list
  380.  
  381.         DisposeHandle(shapeHdl);
  382.         if (fontList)
  383.             DisposePtr((Ptr)fontList);
  384.     }
  385.     return dataHdl;
  386.  
  387. } // CreateQDGXStream
  388.  
  389. // --------------------------------------------------------------------------------------------------------------
  390. static PicHandle DecompressShape(gxShape theShape, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  391. /*
  392.  *    This guy returns a Quickdraw picture containing an embedded shape, and a proxie
  393.  *    of the shape, if proxie is not nil. This is called by ShapeToScrap and DragAndDropShape.
  394.  *
  395.  *    theShape            • the shape you want to embedd in a PICT
  396.  *    proxie            • a PICT to be drawn if theShape cannot be drawn (optional but recommended)
  397.  *    forPrintingOnly        • if TRUE, then the decompressor will always look for the proxie
  398.  *                    and theShape will only be used when printing. Use this setting if
  399.  *                    theShape might be too large or too slow when drawn from other apps.
  400.  *                    • If FALSE, then the decompressor will draw theShape unless it
  401.  *                    gets an error, in which case it will look for a proxie.
  402.  *    eraseBackground    • if TRUE, the decompressor will always erase the background to WHITE
  403.  *                    before drawing the shape. This is slower, but needed if the shape does not
  404.  *                    fill its bounding rectangle.
  405.  *                    • if FALSE, the decompressor will just draw the shape. Use this setting
  406.  *                    if the shape entirely fills its bounding rectangle.
  407.  *
  408.  *    The shape [and proxie] is embedded by constructing a stream of atoms. Each atom begins
  409.  *    with a size (long) and a type (OSType) and then the data for that type. After the last atom,
  410.  *    there is a trailing zero (long) to mark the end of the stream. For embedded shapes, the type
  411.  *    is 'qdgx', and for the proxie the type is 'PICT'. Note that the size fields are rounded up to
  412.  *    a multiple of 4. Finally, to alert QuickTime that the data is in this parsable form with a
  413.  *    possible PICT proxie, we add a 'prxy' extension to the ImageDescriptionHandle.
  414.  *
  415.  *    Picture of this form will draw the embedded shape when an application calls DrawPicture
  416.  *    if GX is around, and if not, the proxie will be drawn. When printed, the shape or the proxie
  417.  *    will be printed. This is meant to replace the PicComment described in GX 1.0 for embedding
  418.  *    shapes in pictures.
  419.  *
  420.  *    If you want to include a flatFontList tag, be sure that theShape is a picture, otherwise GX will
  421.  *    not return the tag after GXFlattenShape. The flatFontList tag makes certain printing conditions
  422.  *    more efficient (i.e. font downloading to postscript printers).
  423.  *
  424.  *    Your shape must not contain a gxQuickDrawPictTag, meaning it contains embedded QD data, becuase
  425.  *    this will potentially crash when it tries to print. To fix that, DecompressShape looks for occurrences
  426.  *    of the tag, and converts them to real gx data by calling GXSetShapeType(shape, gxPictureType).
  427. */
  428. {
  429.     PicHandle                thePicture;
  430.     ImageDescriptionHandle    descHdl;
  431.     ImageDescriptionPtr        descPtr;
  432.     Handle                    dataHdl;
  433.     CGrafPtr                 thePort;
  434.     if (!gMachineInfo.haveQuickTime)
  435.         return nil;
  436.  
  437.     /*
  438.      *    Move the shape's topLeft to 0,0 so that it draws neatly inside the picture frame.
  439.      *    Note that the qdgx movie library does not move the shape, since the shape may not
  440.      *    take up the whole frame.
  441.     */
  442.     {    
  443.         gxRectangle    bounds;
  444.  
  445.         GXGetShapeLocalBounds(theShape, &bounds);
  446.         if (bounds.left || bounds.top)
  447.             GXMoveShape(theShape, -bounds.left, -bounds.top);
  448.         dataHdl = CreateQDGXStream(theShape, proxie, forPrintingOnly, eraseBackground);
  449.         if (bounds.left || bounds.top)
  450.             GXMoveShape(theShape, bounds.left, bounds.top);
  451.     }
  452.     if (dataHdl == nil)
  453.         return nil;
  454.  
  455.     descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  456.     if (descHdl)
  457.         {    
  458.         Rect            shortBounds;
  459.         gxRectangle    bounds;
  460.  
  461.         GXGetShapeLocalBounds(theShape, &bounds);
  462.         RectangleToRect(&bounds, &shortBounds);
  463.         OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);    // set the topLeft of the src to 0,0
  464.         thePicture = OpenPicture(&shortBounds);
  465.  
  466.         descPtr = *descHdl;
  467.         descPtr->idSize = sizeof(ImageDescription);
  468.         descPtr->cType = 'qdgx';
  469.         descPtr->vendor = 'appl';
  470.         descPtr->temporalQuality = codecLosslessQuality;
  471.         descPtr->width = shortBounds.right;
  472.         descPtr->height = shortBounds.bottom;
  473.         descPtr->hRes = descPtr->vRes = ff(72);
  474.         descPtr->dataSize = GetHandleSize(dataHdl);
  475.         descPtr->frameCount = 1;
  476.         descPtr->depth = 32;
  477.         descPtr->clutID = -1;
  478.  
  479.         //    If there is a PICT proxie, add an image extension to tell QuickTime, in case GX is not around.
  480.         if (proxie)
  481.             {    
  482.             Handle prxyVersionHdl = NewHandle(sizeof(long));
  483.  
  484.             if (prxyVersionHdl != nil)
  485.                 {    
  486.                 *(long*)*prxyVersionHdl = 0;        // version number for 'prxy' extension
  487.                 #if GENERATINGCFM
  488.                     SetImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  489.                 #else
  490.                     AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  491.                 #endif
  492.                 }
  493.             }
  494.  
  495.         HLock(dataHdl);
  496.         thePort = GetQDGlobalsThePort();
  497.         DecompressImage(*dataHdl, descHdl, GetPortPixMap(thePort),
  498.                 &shortBounds, &shortBounds, srcCopy, nil);
  499.         DisposeHandle((Handle)descHdl);
  500.         ClosePicture();
  501.         }
  502.     else
  503.         thePicture = nil;
  504.  
  505.     DisposeHandle(dataHdl);
  506.  
  507.     return thePicture;
  508.     
  509. } // DecompressShape
  510.  
  511. // --------------------------------------------------------------------------------------------------------------
  512. static PicHandle ShapeToPICT(gxShape source)
  513. /*
  514.  *    This guy returns a Quickdraw picture containing a 1-bit bitmap of the shape.
  515.  *    This is used by ShapeToScrap to create a proxie when calling DecompressShape.
  516.  *    If you want to make the proxie prettier (and larger), change the bitmap to 8-bit.
  517.  *    However, if you're using this in conjunction with DecompressShape to place a
  518.  *    gxShape on the clipboard, 1-bit should be enough, since the actual shape will be
  519.  *    drawn, rather than the proxie (unless forPrintingOnly is true).
  520. */
  521. {
  522.     gxRectangle        bounds;
  523.     gxShape            bitShape;
  524.     gxBitmap        bitmap;
  525.     PicHandle        thePicture;
  526.     Rect            shortBounds;
  527.  
  528.     /*
  529.      *    GetShapeLocalBounds doesn't accurately report the bounds of a gxQuickDrawPictTag.
  530.      *    but we should have none of them at this point anyway.
  531.     */
  532.     GXGetShapeLocalBounds(source, &bounds);
  533.     RectangleToRect(&bounds, &shortBounds);
  534.     OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);
  535.  
  536.     bitmap.width        = shortBounds.right;
  537.     bitmap.height        = shortBounds.bottom;
  538.     bitmap.rowBytes        = bitmap.width + 31 >> 5 << 2;
  539.     bitmap.pixelSize    = 1;
  540.     bitmap.space        = gxIndexedSpace;
  541.     bitmap.set            = nil;
  542.     bitmap.profile        = nil;
  543.     bitmap.image        = NewPtrClear(bitmap.rowBytes * bitmap.height);
  544.     if (bitmap.image == nil)
  545.         return nil;
  546.  
  547.     bitShape = GXNewBitmap(&bitmap, nil);
  548.     if (bitShape != nil)
  549.         {    
  550.         gxViewGroup group    = GXNewViewGroup();
  551.         gxViewDevice device    = GXNewViewDevice(group, bitShape);
  552.         gxViewPort port        = GXNewViewPort(group);
  553.         gxTransform trans    = GXCloneTransform(GXGetShapeTransform(source));
  554.  
  555.         GXSetShapeAttributes(source, GXGetShapeAttributes(source) | gxMapTransformShape);
  556.         GXMoveShape(source, -bounds.left, -bounds.top);
  557.         GXSetViewPortDither(port, 4);
  558.         GXSetShapeViewPorts(source, 1, &port);
  559.         GXDrawShape(source);
  560.         GXSetShapeTransform(source, trans);
  561.         GXDisposeTransform(trans);
  562.         
  563.         GXDisposeViewGroup(group);    /* this disposes the gxViewPort and gxViewDevice */
  564.         GXDisposeShape(bitShape);
  565.         }
  566.  
  567.     {    
  568.         GrafPtr    thePort;
  569.         BitMap    srcBits;
  570.     
  571.         GetPort(&thePort);
  572.         srcBits.baseAddr = bitmap.image;
  573.         srcBits.rowBytes = bitmap.rowBytes;
  574.         srcBits.bounds = shortBounds;
  575.  
  576.         thePicture = OpenPicture(&shortBounds);
  577.         CopyBits(&srcBits, &thePort->portBits, &shortBounds, &shortBounds, srcOr, nil);
  578.         ClosePicture();
  579.     }
  580.     
  581.     DisposePtr((Ptr)bitmap.image);
  582.     
  583.     return thePicture;
  584.     
  585. } // ShapeToPICT
  586.  
  587.  
  588.  
  589. // --------------------------------------------------------------------------------------------------------------
  590.  
  591. static void GetRidOfAnyQDShapeTags(gxShape shape)
  592. {
  593.     gxShapeType shapeType = GXGetShapeType(shape);
  594.  
  595.     if (shapeType == gxPictureType)
  596.         {    
  597.         long        index, count;
  598.         gxShape        contentShape;
  599.     
  600.         count = GXGetPicture(shape, nil, nil, nil, nil);
  601.         for (index = 0; index < count; index++)
  602.             {
  603.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, nil);
  604.             GetRidOfAnyQDShapeTags(contentShape);
  605.             }
  606.         }
  607.     else 
  608.         {
  609.         if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  610.             GXSetShapeType(shape, gxPictureType);
  611.         }
  612.             
  613. } // GetRidOfAnyQDShapeTags
  614.  
  615. // --------------------------------------------------------------------------------------------------------------
  616.  
  617. static void ShapeToScrap(gxShape source)
  618. /*
  619.  *    This guy puts a Quickdraw picture on the clipboard containing an embedded shape
  620.  *    and, if addProxie is true, a 1-bit bitmap of the shape. Call this in response to
  621.  *    the user choosing "Copy" or "Cut" from the Edit menu. See comment for DecompressShape
  622.  *    to explain forPrintingOnly.
  623. */
  624. {
  625.     PicHandle    picture, proxy;
  626.     
  627.     proxy = ShapeToPICT(source);
  628.     picture = DecompressShape(source, proxy, false, true);
  629.     if (proxy)
  630.         KillPicture(proxy);
  631.  
  632.     if (picture)
  633.         {    
  634.         HLock((Handle)picture);
  635.         ZeroScrap();
  636.         PutScrap(GetHandleSize((Handle)picture), 'PICT', (Ptr)*picture);
  637.         KillPicture(picture);
  638.         }
  639.         
  640. } // ShapeToScrap
  641.  
  642. // --------------------------------------------------------------------------------------------------------------
  643.  
  644. static void CullShape(gxShape shape, gxShape addToThis, gxRectangle *pCullRect, gxStyle cullStyle, gxInk cullInk, gxTransform cullTransform)
  645. /*
  646.     Add to "addToThis" the "shape", only if the shape intersects the pCullRect.
  647. */
  648. {
  649.     gxShapeType shapeType = GXGetShapeType(shape);
  650.  
  651.     if (shapeType == gxPictureType)
  652.         {    
  653.         long        index, count;
  654.         gxShape        contentShape;
  655.     
  656.         count = GXGetPicture(shape, nil, nil, nil, nil);
  657.         for (index = 0; index < count; index++)
  658.             {
  659.             GXGetPictureParts(shape, index+1, 1, &contentShape, &cullStyle, &cullInk, &cullTransform);
  660.             CullShape(contentShape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  661.             }
  662.         }
  663.     else 
  664.         {
  665.         gxRectangle    bounds;
  666.         
  667.         GXGetShapeLocalBounds(shape, &bounds);
  668.         
  669.         if (IsSomewhereInRectangle(pCullRect, &bounds))
  670.             {
  671.             if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  672.                 {
  673.                 // convert shape and add -- but only if it goes okay
  674.                 GXSetShapeType(shape, gxPictureType);
  675.                 if (GXGetShapeType(shape) == gxPictureType)
  676.                     CullShape(shape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  677.                 }
  678.             else
  679.                 {
  680.                 GXSetPictureParts(addToThis, 0, 0, 1, &shape, &cullStyle, &cullInk, &cullTransform);
  681.                 }
  682.             }
  683.         }
  684.         
  685. } // CullShape
  686.  
  687. // --------------------------------------------------------------------------------------------------------------
  688. static gxShape CullPicture(gxShape pictureShape, gxRectangle * pCullRect)
  689. /*
  690.     Returns a new shape that is all of the shapes inside of pictureShape
  691.     that intersect pCullRect.
  692. */
  693. {
  694.     gxShape        newPicture = GXNewShape(gxPictureType);
  695.     gxShape     clipShape = GXNewRectangle(pCullRect);
  696.     gxMapping    mapping;
  697.     gxRectangle    clipRect;
  698.     
  699.     // new shape as same mapping as old one
  700.     GXGetTransformMapping(GXGetShapeTransform(pictureShape), &mapping);
  701.     GXSetShapeMapping(newPicture, &mapping);
  702.     
  703.     // clip also has the mapping, but inverted so that it's the right space
  704.     InvertMapping(&mapping, &mapping);
  705.     GXMapShape(clipShape, &mapping);
  706.     GXGetShapeLocalBounds(clipShape, &clipRect);
  707.     
  708.     // clip to the selection
  709.     GXSetShapeClip(newPicture, clipShape);
  710.     GXDisposeShape(clipShape);
  711.  
  712.     // add all shapes that intersect the clip area
  713.     CullShape(pictureShape, newPicture, &clipRect, nil, nil, nil);
  714.         
  715.     // new shape is zero based
  716.     GXMoveShape(newPicture, -pCullRect->left, -pCullRect->top);
  717.     
  718.     return(newPicture);
  719.     
  720. } // CullPicture
  721.  
  722. // --------------------------------------------------------------------------------------------------------------
  723. static gxShape GetSelectedShape(WindowDataPtr pData)
  724. /*
  725.     Returns a shape that represents all shapes on the current page
  726.     that are contained by the current selection rectangle.
  727. */
  728. {
  729.     gxRectangle        cullRect;
  730.     gxShape            cullShape;
  731.     gxPoint            offset;
  732.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  733.     
  734.     // calculate the actual coodinate space, removing margins
  735.     {
  736.     gxRectangle        pageSize, paperSize;
  737.     
  738.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  739.     offset.y = FixedMultiply(-paperSize.top, zoomFactor);
  740.     offset.x = FixedMultiply(-paperSize.left, zoomFactor);
  741.     }
  742.     
  743.     // calculate the actual coodinates to copy
  744.     cullRect.top    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.top) - offset.y, zoomFactor);
  745.     cullRect.left    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.left) - offset.x, zoomFactor);
  746.     cullRect.bottom    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.bottom) - offset.y, zoomFactor);
  747.     cullRect.right    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.right) - offset.x, zoomFactor);
  748.     
  749.     // chop the data
  750.     cullShape = CullPicture(((GXDataPtr)pData)->currentPageShape, &cullRect);
  751.     
  752.     return(cullShape);
  753.     
  754. } // GetSelectedShape
  755.  
  756. // --------------------------------------------------------------------------------------------------------------
  757. static pascal OSErr GXSendDataProc(FlavorType theType, void *dragSendRefCon,
  758.                                 ItemReference theItem, DragReference theDrag)
  759. /*
  760.  *    The ItemReference is the gxShape to be sent. The dragSendRefCon is ignored.
  761. */
  762. {
  763. #pragma unused (theItem)
  764.  
  765.     OSErr    result = noErr;
  766.     gxShape    shape = ((GXDataPtr)dragSendRefCon)->tempDragShape;
  767.     
  768.     // haven't made clipped version yet?
  769.     if (shape == nil)
  770.         {
  771.         shape = GetSelectedShape((WindowDataPtr) dragSendRefCon);
  772.         ((GXDataPtr)dragSendRefCon)->tempDragShape = shape;
  773.         }
  774.         
  775.     switch (theType) 
  776.         {
  777.         case 'qdgx':
  778.             {    
  779.             Handle         flat;
  780.               userSpool     block;
  781.  
  782.             block.spool.spoolProcedure = gHandleSpoolProc;
  783.             block.spool.buffer = nil;
  784.             block.spool.bufferSize = 0;
  785.             GXFlattenShape(shape, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  786.             flat = (Handle) block.data;
  787.     
  788.             if (flat)
  789.                 {    
  790.                 HLock(flat);
  791.                 result = SetDragItemFlavorData(theDrag, 1, 'qdgx', *flat, GetHandleSize(flat), 0);
  792.                 DisposeHandle(flat);
  793.                 }
  794.             }
  795.             break;
  796.             
  797.         case 'PICT':
  798.             {    
  799.             PicHandle proxie = ShapeToPICT(shape);
  800.             PicHandle pict = DecompressShape(shape, proxie, false, true);
  801.     
  802.             if (proxie)
  803.                 KillPicture(proxie);
  804.             if (pict)
  805.                 {    
  806.                 HLock((Handle)pict);
  807.                 result = SetDragItemFlavorData(theDrag, 1, 'PICT', (Ptr)*pict, GetHandleSize((Handle)pict), 0);
  808.                 KillPicture(pict);
  809.                 }
  810.             }
  811.             break;
  812.             
  813.         default:
  814.             result = badDragFlavorErr;
  815.             break;
  816.         }
  817.             
  818.     return result;
  819.     
  820. } // GXSendDataProc
  821.  
  822. #if GENERATINGCFM
  823.     static RoutineDescriptor gGXSendDataProcRD = BUILD_ROUTINE_DESCRIPTOR(uppDragSendDataProcInfo, GXSendDataProc);
  824.     static DragSendDataUPP gGXSendDataProc = &gGXSendDataProcRD;
  825. #else
  826.     static DragSendDataUPP gGXSendDataProc = NewDragSendDataUPP(GXSendDataProc);
  827. #endif
  828.  
  829. // --------------------------------------------------------------------------------------------------------------
  830. static void ClearCurrentSelection(GXDataPtr pData)
  831. {
  832.     pData->currentShapeIndex = 0;
  833.     pData->currentShapeStart = 0;
  834.     pData->currentShapeEnd = 0;
  835.     if (pData->currentSelectionShape)
  836.         {
  837.         GXDisposeShape(pData->currentSelectionShape);
  838.         pData->currentSelectionShape = nil;
  839.         }
  840.         
  841. } // ClearCurrentSelection
  842.  
  843. // --------------------------------------------------------------------------------------------------------------
  844. static OSErr    GetCurrentPage(GXDataPtr pData, Boolean disposeOfSelection)
  845. /*
  846.     Disposes of previously loaded page information, and loads the
  847.     page information for the current page number.
  848. */
  849. {
  850.     OSErr        anErr;
  851.     LongRect    oldRect, newRect;
  852.     
  853.     if (pData->numberOfPages != 0)
  854.         {
  855.         // get rid of any previous format
  856.         if (pData->currentPageFormat)
  857.             {
  858.             GXDisposeFormat(pData->currentPageFormat);
  859.             pData->currentPageFormat = nil;
  860.             }
  861.             
  862.         // get rid of any previous shape
  863.         if (pData->currentPageShape)
  864.             {
  865.             GXDisposeShape(pData->currentPageShape);
  866.             pData->currentPageShape = nil;
  867.             }
  868.             
  869.         // get rid of selection, if desired
  870.         if (disposeOfSelection)
  871.             ClearCurrentSelection(pData);
  872.  
  873.         GXGetDocumentRect((WindowPtr)pData, (WindowDataPtr)pData, &oldRect, false);
  874.         
  875.         GXReadPrintFilePage(pData->thePrintFile, 
  876.             pData->currentPage, 
  877.             1, &pData->childViewPort, 
  878.             &pData->currentPageFormat, &pData->currentPageShape);
  879.         }
  880.         
  881.     anErr = GXGetJobError(pData->w.hPrint);
  882.     
  883.     if (anErr == noErr)
  884.         {
  885.         GXGetDocumentRect((WindowPtr)pData,(WindowDataPtr) pData, &newRect, false);
  886.         
  887.         if     (
  888.             (oldRect.left != newRect.left) ||
  889.             (oldRect.top != newRect.top) ||
  890.             (oldRect.right != newRect.right) ||
  891.             (oldRect.bottom != newRect.bottom)
  892.             )
  893.             {
  894.             // if the resulting page is < the current window size, we need to resize,
  895.             long newWidth     = newRect.right - newRect.left + kScrollBarSize;
  896.             long newHeight     = newRect.bottom - newRect.top + kScrollBarSize;
  897.             long oldWidth     = pData->w.theWindow.port.portRect.right - pData->w.theWindow.port.portRect.left;
  898.             long oldHeight     = pData->w.theWindow.port.portRect.bottom - pData->w.theWindow.port.portRect.top;
  899.             
  900.             // but don't let it get too small!
  901.             if (newWidth < pData->w.minHSize)
  902.                 newWidth = pData->w.minHSize;
  903.             if (newHeight < kMinGXDocSize)
  904.                 newHeight = kMinGXDocSize;
  905.                 
  906.             if     (
  907.                 (newWidth < oldWidth) ||
  908.                 (newHeight < oldHeight)
  909.                 )
  910.                 {
  911.                 if (newWidth > oldWidth)
  912.                     newWidth = oldWidth;
  913.                 if (newHeight > oldHeight)
  914.                     newHeight = oldHeight;
  915.                     
  916.                 SizeWindow((WindowPtr)pData, newWidth, newHeight, false);
  917.                 }
  918.                 
  919.             // and in any case, the scroll bars should update
  920.             AdjustScrollBars((WindowPtr)pData, true, true, nil);
  921.             }
  922.         }
  923.         
  924.     return(anErr);
  925.     
  926. } // GetCurrentPage
  927.  
  928. // --------------------------------------------------------------------------------------------------------------
  929. #define charBullet    '•'
  930.  
  931. static void GetIntlTokenChar(short whichToken, short whichScript, char *bulletString)
  932. //
  933. // GetIntlTokenChar
  934. //
  935. // This routine gets a character out of the itl4 given a script and token…
  936. //
  937. {
  938.     Handle    itl4H;
  939.     long    offset, len;
  940.  
  941.     // default the value
  942.     bulletString[0] = 1;
  943.     bulletString[1] = charBullet;
  944.     
  945.     // Look up the untoken table -- bail if we can’t get it
  946.     GetIntlResourceTable(whichScript, iuUnTokenTable, &itl4H, &offset, &len);
  947.     if (itl4H && (offset > 0) && (len >= 0))
  948.     {
  949.         char *sp = (*itl4H + offset);                // Point to start of untoken table
  950.         if (whichToken <= ((short *)sp)[1])            // Check if token has valid index
  951.         {
  952.             sp += ((short *)sp)[2+whichToken];        // Add the string offset and voliá!
  953.             BlockMoveData(sp, bulletString, sp[0]+1);
  954.         }
  955.     }
  956.     
  957. } // GetIntlTokenChar
  958.  
  959. // --------------------------------------------------------------------------------------------------------------
  960. // This code is required to change pop up menus to a different font size.  It would be
  961. // better to use the pop up control, but it doesn't allow multiple items to be marked.
  962.  
  963. #define SysFontSize    0xBA8
  964. #define SysFontFam    0xBA6
  965. #define CurFMInput    0x988
  966.  
  967. static void DoUseWFont(TextState *savedInfo, WindowPtr owner,  Boolean saveIt)
  968. /*************************************************************
  969.     DoUseWFont        - Sets the font mgr low mem globals so
  970.                         we can have Geneva 9 popups
  971.  
  972.         savedInfo    - Fills it in if saveIt = true, else
  973.                         it sets the port to those values
  974.         owner        - Where to get the original values
  975.         saveIt        - true for save
  976. **************************************************************/
  977. {
  978.     TextState        myState,
  979.                     *theState;
  980.     short            aFont;
  981.  
  982.     theState = savedInfo;
  983.  
  984.     if (saveIt) 
  985.         {
  986.         savedInfo->theFont = GetSysFont();    // save low memory globals
  987.         savedInfo->theSize = *((short *) SysFontSize);
  988.  
  989.         myState.theFont = GetWindowPort(owner)->txFont;
  990.         myState.theSize = GetWindowPort(owner)->txSize;
  991.         theState = &myState;
  992.  
  993.         // if we stuff systemFont, it will screw up Script Mgr
  994.         if (GetWindowPort(owner)->txFont == systemFont)
  995.             goto dosizestuff;
  996.         }
  997.  
  998.     // if we stuff applFont, this will also screw up Script Mgr
  999.     // instead we get the actual font
  1000.     aFont = theState->theFont;
  1001.     if (saveIt)
  1002.         if (GetWindowPort(owner)->txFont == applFont)
  1003.             aFont = GetAppFont();
  1004.     *((short *) SysFontFam) = aFont;                    // set/restore low memory globals
  1005.  
  1006. dosizestuff:
  1007.     *((short *) SysFontSize) = theState->theSize;
  1008.  
  1009.     *((long *) CurFMInput) = 0xFFFFFFFF;
  1010.     
  1011. } // DoUseWFont
  1012.  
  1013.  
  1014. // --------------------------------------------------------------------------------------------------------------
  1015.  
  1016. static void SetZoom(WindowPtr pWindow, WindowDataPtr pData, Fixed newZoom)
  1017. /*
  1018.     Sets the new zoom factor for the window, causing an update for
  1019.     the window if required.
  1020. */
  1021. {
  1022.     Fixed    scaleFactor;
  1023.     
  1024.     // pin to max/min zoom factors
  1025.     if (newZoom > ff(32))
  1026.         newZoom = ff(32);
  1027.     if (newZoom < 0x0800)
  1028.         newZoom = 0x0800;
  1029.     
  1030.     scaleFactor = FixedDivide(newZoom, ((GXDataPtr)pData)->zoomFactor);
  1031.     
  1032.     if (scaleFactor != ff(1))
  1033.         {
  1034.         gxPoint        centerPoint;
  1035.         GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1036.         
  1037.         // zoom about the window center
  1038.         centerPoint.x = ff(pPort->portRect.left + (RectWidth(pPort->portRect) >> 1));
  1039.         centerPoint.y = ff(pPort->portRect.top + (RectHeight(pPort->portRect) >> 1));
  1040.         
  1041.         // new zoom active
  1042.         ((GXDataPtr)pData)->zoomFactor = newZoom;
  1043.         
  1044.         // force update and recalc the size of window
  1045.         InvalRect(&pPort->portRect);
  1046.         AdjustScrollBars(pWindow, true, true, nil);
  1047.  
  1048.          // scale scroll values
  1049.         SetControlValue(pData->hScroll, FixedToInt( FixedDivide(centerPoint.x, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->hScroll)), scaleFactor) ) );
  1050.         SetControlValue(pData->vScroll, FixedToInt( FixedDivide(centerPoint.y, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->vScroll)), scaleFactor) ) );
  1051.         
  1052.         // zoom the selection
  1053.         ((GXDataPtr)pData)->selectionRectangle.left     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.left), scaleFactor) );
  1054.         ((GXDataPtr)pData)->selectionRectangle.top         = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.top), scaleFactor) );
  1055.         ((GXDataPtr)pData)->selectionRectangle.right     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.right), scaleFactor) );
  1056.         ((GXDataPtr)pData)->selectionRectangle.bottom     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.bottom), scaleFactor) );
  1057.         }
  1058.     
  1059. } // SetZoom
  1060.  
  1061. // --------------------------------------------------------------------------------------------------------------
  1062.  
  1063. static void SetShapeGreyColorLevel(gxShape thisShape, unsigned long greyLevel)
  1064. {
  1065.     gxColor thisColor;
  1066.  
  1067.     thisColor.space = gxGraySpace;
  1068.     thisColor.profile = nil;
  1069.     thisColor.element.gray = greyLevel;
  1070.     GXSetShapeColor(thisShape, &thisColor);
  1071.     
  1072. } // SetShapeGreyColorLevel
  1073.  
  1074. // --------------------------------------------------------------------------------------------------------------
  1075. static void    CenterRect(Rect *source, Rect *against)
  1076. /*
  1077.     Centers "source" within or around "against".
  1078. */
  1079. {
  1080.     // center picture if requested
  1081.     short    height, width, pheight, pwidth;
  1082.     
  1083.     height = (against->bottom - against->top) >> 1;
  1084.     width = (against->right - against->left) >> 1;
  1085.     pheight = (source->bottom - source->top) >> 1;
  1086.     pwidth = (source->right - source->left) >> 1;
  1087.     
  1088.     source->top = against->top + height - pheight;
  1089.     source->bottom = against->bottom - height + pheight;
  1090.     source->left = against->left + width - pwidth;
  1091.     source->right = against->right - width + pwidth;
  1092.  
  1093. } // CenterRect
  1094.  
  1095. // --------------------------------------------------------------------------------------------------------------
  1096.  
  1097. static gxShape FindNestedIndexedLayout(gxShape shape, 
  1098.                     long searchIndex, long * pIndex, gxMapping *pConcatMapping)
  1099. /*
  1100.     Returns the shape represented by "searchIndex" shapes into the picture,
  1101.     sequentially, including all nestings of pictures.  Uses pIndex as
  1102.     work storage, which must be initialized to zero before the call.
  1103.     
  1104.     Returns shape found, or NIL if the searchIndex is larger than
  1105.     the number of shapes in the picture.  If NIL is returned,
  1106.     then the contents of pIndex will contain the number of
  1107.     shapes in the picture.
  1108. */
  1109. {
  1110.     gxShape        returnShape = nil;
  1111.     gxShapeType shapeType = GXGetShapeType(shape);
  1112.  
  1113.     // bail on negative index
  1114.     if (searchIndex < 0)
  1115.         return(nil);
  1116.         
  1117.     if (shapeType == gxPictureType)
  1118.         {    
  1119.         long        index, count;
  1120.         gxShape        contentShape;
  1121.         gxTransform    contentTransform;
  1122.         gxMapping    contentMapping;
  1123.         
  1124.         count = GXGetPicture(shape, nil, nil, nil, nil);
  1125.         for (index = 0; index < count; index++)
  1126.             {
  1127.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, &contentTransform);
  1128.             
  1129.             returnShape = FindNestedIndexedLayout(contentShape, searchIndex, pIndex, pConcatMapping ? &contentMapping : nil);
  1130.             if (returnShape)
  1131.                 {
  1132.                 if (pConcatMapping)
  1133.                     {
  1134.                     if (!contentTransform)
  1135.                         contentTransform = GXGetShapeTransform(contentShape);
  1136.                     GXGetTransformMapping(contentTransform, &contentMapping);
  1137.                     MapMapping(&contentMapping, pConcatMapping);
  1138.                     *pConcatMapping = contentMapping;
  1139.                     }
  1140.                 break;
  1141.                 }
  1142.             }
  1143.         }
  1144.     else 
  1145.         {
  1146.         if ( (shapeType == gxLayoutType) || (shapeType == gxGlyphType) || (shapeType == gxTextType) )
  1147.             {
  1148.             (*pIndex)++;
  1149.             if (searchIndex == *pIndex)
  1150.                 returnShape = shape;
  1151.             }
  1152.         }
  1153.         
  1154.     return(returnShape);
  1155.     
  1156. } // FindNestedIndexedLayout
  1157.  
  1158. // --------------------------------------------------------------------------------------------------------------
  1159. static Boolean PerformNextFind(WindowPtr pWindow, WindowDataPtr pData,
  1160.                 Str255 findString,
  1161.                 Boolean caseSensitive,
  1162.                 Boolean backwards,
  1163.                 Boolean wraparound)
  1164. {
  1165.     Boolean    foundSomething = false;
  1166.     long    searchIndex, workIndex;
  1167.     gxShape    aShape;
  1168.     long    direction;
  1169.     long    oldPageNumber = ((GXDataPtr)pData)->currentPage;
  1170.     long    endPageNumber;
  1171.     Boolean    firstTime = true;
  1172.     gxMapping    concatMapping;
  1173.     
  1174.     // initialize direction of the walk
  1175.     if (backwards)
  1176.         direction = -1;
  1177.     else
  1178.         direction = 1;
  1179.     
  1180.     // start searching where we last left off    
  1181.     searchIndex = ((GXDataPtr)pData)->currentShapeIndex;
  1182.     if (searchIndex != 0)
  1183.         searchIndex -= direction;
  1184.     
  1185.     if (((GXDataPtr)pData)->numberOfPages == 1)
  1186.         wraparound = false;
  1187.  
  1188.     // end searching on a particular page
  1189.     if (backwards)
  1190.         endPageNumber = 0;
  1191.     else
  1192.         endPageNumber = ((GXDataPtr)pData)->numberOfPages + 1;
  1193.     
  1194.     // can't search on qd shapes, so we get rid of them
  1195.     GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1196.  
  1197.     do
  1198.         {
  1199.         // search for the next shape or prev shape
  1200.         searchIndex += direction;
  1201.         
  1202.         // initialize the working index so that we know traversal level
  1203.         workIndex = 0;
  1204.         
  1205.         // initialize the mapping to identity
  1206.         ResetMapping(&concatMapping);
  1207.         GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &concatMapping);
  1208.         
  1209.         // find the next layout in the page
  1210.         aShape = FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, searchIndex, &workIndex, &concatMapping);
  1211.         if (aShape)
  1212.             {
  1213.             gxShapeType shapeType = GXGetShapeType(aShape);
  1214.             long          size;
  1215.             Handle        aHandle;
  1216.             
  1217.             // determine size and allocate storage for layout contents
  1218.             switch (shapeType)
  1219.                 {
  1220.                 case gxTextType:
  1221.                     size = GXGetText(aShape, nil, nil, nil);
  1222.                     break;
  1223.                 case gxGlyphType:
  1224.                     size = GXGetGlyphs(aShape, nil, nil, nil,
  1225.                                     nil, nil, nil, nil, nil);
  1226.                     break;
  1227.                 case gxLayoutType:
  1228.                     size = GXGetLayout(aShape, nil,
  1229.                                     nil, nil, nil,     // styles
  1230.                                     nil, nil, nil,     // levels
  1231.                                     nil, nil);        // options/position
  1232.                     break;
  1233.                 }
  1234.             aHandle = NewHandle(size);
  1235.             
  1236.             if (aHandle)
  1237.                 {
  1238.                 long newStart, newEnd;
  1239.                 
  1240.                 // grab the contents of the layout into the temp storage
  1241.                 HLock(aHandle);
  1242.                 switch (shapeType)
  1243.                     {
  1244.                     case gxTextType:
  1245.                         GXGetText(aShape, nil, (unsigned char*)*aHandle, nil);
  1246.                         break;
  1247.                     case gxGlyphType:
  1248.                         GXGetGlyphs(aShape, nil,  (unsigned char*)*aHandle, nil,
  1249.                                         nil, nil, nil, nil, nil);
  1250.                         break;
  1251.                     case gxLayoutType:
  1252.                         GXGetLayout(aShape,  (unsigned char*)*aHandle,
  1253.                                     nil, nil, nil,     // styles
  1254.                                     nil, nil, nil,     // levels
  1255.                                     nil, nil);        // options/position
  1256.                         break;
  1257.                     }
  1258.                 HUnlock(aHandle);
  1259.                 
  1260.                 // search the handle for the string we're looking for,
  1261.                 // but don't wraparound because we handle that over layout
  1262.                 // ranges and pages ourselves
  1263.                 {
  1264.                 long offset;
  1265.                 
  1266.                 if ((firstTime) && (((GXDataPtr)pData)->currentSelectionShape))
  1267.                     {
  1268.                     // for shape that we have found something in before
  1269.                     // start at end of last point if forwards, start of last point
  1270.                     // if backwards
  1271.                     firstTime = false;
  1272.                     offset = backwards ? ((GXDataPtr)pData)->currentShapeStart : ((GXDataPtr)pData)->currentShapeEnd;
  1273.                     }
  1274.                 else
  1275.                     {
  1276.                     // for "new" shape we haven't hit before, start at
  1277.                     // begining for forwards, end for backwards
  1278.                     offset = backwards ? size : 0;
  1279.                     }
  1280.                     
  1281.                 foundSomething = PerformSearch(aHandle, offset, findString, 
  1282.                             caseSensitive, backwards, false,
  1283.                             &newStart, &newEnd);
  1284.                 }
  1285.                             
  1286.                 // done with our temp storage
  1287.                 DisposeHandle(aHandle);
  1288.                 
  1289.                 // got it?  then mark it and bail out
  1290.                 if (foundSomething)
  1291.                     {
  1292.                     // remember where we are in the page
  1293.                     ((GXDataPtr)pData)->currentShapeIndex = searchIndex;
  1294.                     
  1295.                     // what offsets the selection is
  1296.                     ((GXDataPtr)pData)->currentShapeStart = newStart;
  1297.                     ((GXDataPtr)pData)->currentShapeEnd = newEnd;
  1298.                     
  1299.                     // and the shape containing the selection
  1300.                     if (((GXDataPtr)pData)->currentSelectionShape)
  1301.                         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1302.                     ((GXDataPtr)pData)->currentSelectionShape = GXCloneShape(aShape);
  1303.                     ((GXDataPtr)pData)->currentSelectionMapping = concatMapping;
  1304.                     break;
  1305.                     } // found the string
  1306.                     
  1307.                 } // allocated the handle
  1308.                 
  1309.             } // found a shape
  1310.         else
  1311.             {
  1312.             OSErr    anErr = noErr;
  1313.             
  1314.             // didn't find it on this page, move on
  1315.             ((GXDataPtr)pData)->currentPage += direction;
  1316.             
  1317.                 
  1318.             // clamp to the ends of the range
  1319.             if (backwards)
  1320.                 {
  1321.                 if (((GXDataPtr)pData)->currentPage <= endPageNumber)
  1322.                     {
  1323.                     if (wraparound)
  1324.                         {
  1325.                         ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  1326.                         endPageNumber = oldPageNumber;
  1327.                         wraparound = false;
  1328.                         }
  1329.                     else
  1330.                         anErr = paramErr;
  1331.                     }
  1332.                 }
  1333.             else
  1334.                 {
  1335.                 if (((GXDataPtr)pData)->currentPage >= endPageNumber)
  1336.                     {
  1337.                     if (wraparound)
  1338.                         {
  1339.                         ((GXDataPtr)pData)->currentPage = 1;
  1340.                         endPageNumber = oldPageNumber;
  1341.                         wraparound = false;
  1342.                         }
  1343.                     else
  1344.                         anErr = paramErr;
  1345.                     }
  1346.                 }
  1347.                 
  1348.             // fetch contents
  1349.             if (anErr == noErr)
  1350.                 anErr = GetCurrentPage((GXDataPtr) pData, false);
  1351.                 
  1352.             // anything wrong?  then all done searching
  1353.             if (anErr != noErr)
  1354.                 {
  1355.                 break;
  1356.                 }
  1357.             else
  1358.                 {
  1359.                 GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1360.                 if (backwards)
  1361.                     {
  1362.                     workIndex = 0;
  1363.                     (void) FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, 0x7FFFFFF, &workIndex, nil);
  1364.                     searchIndex = workIndex;
  1365.                     }
  1366.                 else
  1367.                     searchIndex = 0;
  1368.                 }
  1369.             }
  1370.         } while (!foundSomething);
  1371.     
  1372.     // if we found something, force and update.  If not, make sure
  1373.     // that the current page is restored to the page we had when 
  1374.     // coming in.
  1375.     if (foundSomething)
  1376.         {
  1377.         InvalRect(&GetWindowPort(pWindow)->portRect);
  1378.         }
  1379.     else
  1380.         {
  1381.         if (oldPageNumber != ((GXDataPtr)pData)->currentPage)
  1382.             {
  1383.             ((GXDataPtr)pData)->currentPage = oldPageNumber;
  1384.             GetCurrentPage((GXDataPtr) pData, false);
  1385.             }
  1386.         }
  1387.     return(foundSomething);
  1388.     
  1389. } // PerformNextFind
  1390.  
  1391. // --------------------------------------------------------------------------------------------------------------
  1392. static gxShape GetCurrentSelectionHighlight(WindowDataPtr pData, Boolean mapIt)
  1393. {
  1394.     gxShape        highlight;
  1395.     
  1396.     highlight = GXGetLayoutHighlight(((GXDataPtr)pData)->currentSelectionShape, 
  1397.                         ((GXDataPtr)pData)->currentShapeStart, ((GXDataPtr)pData)->currentShapeEnd,
  1398.                         gxHighlightAverageAngle, nil);
  1399.                         
  1400.     
  1401.     if (mapIt)
  1402.         GXMapShape(highlight, &((GXDataPtr)pData)->currentSelectionMapping);
  1403.     
  1404.     // draw and dispose of the highlight
  1405.     GXSetShapeViewPorts(highlight, 1, &((GXDataPtr)pData)->childViewPort);
  1406.     GXSetShapeFill(highlight, gxClosedFrameFill);
  1407.     GXSetShapeClip(highlight, nil);
  1408.  
  1409.     return(highlight);
  1410.     
  1411. } // GetCurrentSelectionHighlight
  1412.  
  1413. // --------------------------------------------------------------------------------------------------------------
  1414. static void ScrollFoundShapeIntoView(WindowPtr pWindow, WindowDataPtr pData)
  1415. {
  1416.     gxRectangle    bounds;
  1417.     Point        scrollAmount;
  1418.     Point        controlValues;
  1419.     gxRectangle    windowBounds;
  1420.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1421.     
  1422.     if ( ! (((GXDataPtr)pData)->currentSelectionShape) )
  1423.         return;
  1424.         
  1425.     // cache scroll state
  1426.     controlValues.h = GetControlValue(pData->hScroll);
  1427.     controlValues.v = GetControlValue(pData->vScroll);
  1428.     
  1429.     // calculate visible bounds of window
  1430.     windowBounds.left         = ff(pPort->portRect.left + controlValues.h);
  1431.     windowBounds.right         = ff(pPort->portRect.right - kScrollBarSize + controlValues.h);
  1432.     windowBounds.top         = ff(pPort->portRect.top + controlValues.v);
  1433.     windowBounds.bottom     = ff(pPort->portRect.bottom - kScrollBarSize + controlValues.v);                
  1434.  
  1435.     // grab the bounds of the shape, add on the margins, scale to zoom factor
  1436.     {
  1437.     gxRectangle        pageSize, paperSize;
  1438.     gxShape            highlight = GetCurrentSelectionHighlight(pData, false);
  1439.     
  1440.     GXGetShapeBounds(highlight, 0, &bounds);
  1441.     GXDisposeShape(highlight);
  1442.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1443.     bounds.left     = FixedMultiply(bounds.left - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1444.     bounds.right     = FixedMultiply(bounds.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1445.     bounds.top         = FixedMultiply(bounds.top - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1446.     bounds.bottom     = FixedMultiply(bounds.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1447.     }
  1448.  
  1449.     if     (
  1450.         (bounds.bottom <= windowBounds.top) ||
  1451.         (bounds.top >= windowBounds.bottom) ||
  1452.         (bounds.right <= windowBounds.left) ||
  1453.         (bounds.left >= windowBounds.right) 
  1454.         )
  1455.         {
  1456.         scrollAmount.h = controlValues.h - FixedToInt(bounds.left);
  1457.         scrollAmount.v = controlValues.v - FixedToInt(bounds.top);
  1458.         
  1459.         SetControlAndClipAmount(pData->hScroll, &scrollAmount.h);
  1460.         SetControlAndClipAmount(pData->vScroll, &scrollAmount.v);
  1461.         if ((scrollAmount.h) || (scrollAmount.v))
  1462.             DoScrollContent(pWindow, pData, scrollAmount.h, scrollAmount.v);
  1463.         }
  1464.         
  1465. } // ScrollFoundShapeIntoView
  1466.  
  1467. // --------------------------------------------------------------------------------------------------------------
  1468. static Boolean TrackIn(Rect *pTrackRect, Point clickPoint, Rect *pDrawRect, short inID, short outID)
  1469. {
  1470.     Boolean    in = false;
  1471.     
  1472.     if (PtInRect(clickPoint, pTrackRect))
  1473.         {
  1474.         in = true;
  1475.         
  1476.         PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1477.         while (StillDown())
  1478.             {
  1479.             GetMouse(&clickPoint);
  1480.             
  1481.             if (PtInRect(clickPoint, pTrackRect))
  1482.                 {
  1483.                 if (!in)
  1484.                     {
  1485.                     in = true;
  1486.                     PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1487.                     }
  1488.                 }
  1489.             else
  1490.                 {
  1491.                 if (in)
  1492.                     {
  1493.                     in = false;
  1494.                     PlotIconID(pDrawRect, ttNone, ttNone, outID);
  1495.                     }
  1496.                 }
  1497.             }
  1498.         }
  1499.         
  1500.     return(in);
  1501.     
  1502. } // TrackIn
  1503.  
  1504. // --------------------------------------------------------------------------------------------------------------
  1505. static void DrawPageSliderAndThumb(WindowPtr pWindow, long currentValue, long maxValue)
  1506. {
  1507.     Rect        pageSliderRect;
  1508.     Rect        pageThumbRect;
  1509.     long        pixelValue;
  1510.     Str255        aString;
  1511.     FontInfo    theInfo;
  1512.     PicHandle    proxyHandle;
  1513.     Rect        proxyRect;
  1514.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1515.     
  1516.     // calculate location of the slider
  1517.     pageSliderRect.left     = kPageSliderMargins;
  1518.     pageSliderRect.bottom     = pPort->portRect.bottom - kPageSliderMargins;
  1519.     pageSliderRect.top         = pageSliderRect.bottom - kPageSliderHeight;
  1520.     pageSliderRect.right     = pPort->portRect.right - kPageSliderMargins;
  1521.         
  1522.     // then calculate the thumb within that slider
  1523.     pixelValue = (currentValue-1) 
  1524.                 *
  1525.                 (pageSliderRect.right - pageSliderRect.left - kPageThumbMargins*2 - kPageThumbWidth) 
  1526.                 /
  1527.                 (maxValue-1);
  1528.                 
  1529.     pageThumbRect.left         = pageSliderRect.left + kPageThumbMargins + pixelValue;
  1530.     pageThumbRect.right        = pageThumbRect.left + kPageThumbWidth;
  1531.     pageThumbRect.top        = pageSliderRect.top - kPageThumbEdge;
  1532.     pageThumbRect.bottom    = pageThumbRect.top + kPageThumbHeight;
  1533.  
  1534.     // and finally, the location to draw the proxy (if any)
  1535.     proxyRect.top            = kPageSliderMargins;
  1536.     proxyRect.bottom        = proxyRect.top + kProxyHeight;
  1537.     proxyRect.left            = pPort->portRect.left + 
  1538.                                 ((pPort->portRect.right - pPort->portRect.left) >> 1) -
  1539.                                 (kProxyWidth >> 1);
  1540.     proxyRect.right            = proxyRect.left + kProxyWidth;
  1541.     if (Count1Resources(kProxyType) == 0)
  1542.         proxyRect.bottom = proxyRect.top;
  1543.         
  1544.     // draw the slider area
  1545.     FillRect(&pageSliderRect, &qd.gray);
  1546.     FrameRect(&pageSliderRect);
  1547.  
  1548.     // erase areas above and below the slider (old thumb erase)
  1549.     {
  1550.     Rect    sliderEraseRect = pageSliderRect;
  1551.     
  1552.     ForeColor(whiteColor);
  1553.     sliderEraseRect.top = pageThumbRect.top;
  1554.     sliderEraseRect.bottom = sliderEraseRect.top + kPageThumbEdge;
  1555.     PaintRect(&sliderEraseRect);
  1556.     sliderEraseRect.bottom = pageThumbRect.bottom;
  1557.     sliderEraseRect.top = sliderEraseRect.bottom - kPageThumbEdge;
  1558.     PaintRect(&sliderEraseRect);
  1559.     }
  1560.     
  1561.     // draw the thumb
  1562.     ForeColor(blackColor);
  1563.     FrameRect(&pageThumbRect);
  1564.     InsetRect(&pageThumbRect, 1, 1);
  1565.     ForeColor(whiteColor);
  1566.     FrameRect(&pageThumbRect);
  1567.     InsetRect(&pageThumbRect, 1, 1);
  1568.     ForeColor(blackColor);
  1569.     FrameRect(&pageThumbRect);
  1570.  
  1571.     // draw page string label
  1572.     TextFace(bold);
  1573.     TextFont(applFont);
  1574.     TextSize(9);
  1575.     TextMode(srcCopy);
  1576.     GetFontInfo(&theInfo);
  1577.     
  1578.     MoveTo(pageSliderRect.left, pageThumbRect.top - kPageThumbEdge - theInfo.descent);
  1579.     GetIndString(aString, kPageControlStrings, iGoToPageString);
  1580.     DrawString(aString);
  1581.     NumToString(currentValue, aString);
  1582.     DrawString(aString);
  1583.     
  1584.     // erase any trailing digits (pretty cheezy, but seems to work)
  1585.     DrawString("\p       ");
  1586.     
  1587.     // draw the proxy, or erase the proxy area if no picture to draw
  1588.     proxyHandle = (PicHandle) GetResource(kProxyType, kProxyBaseID + currentValue - 1);
  1589.     if (proxyHandle)
  1590.         {
  1591.         Rect    drawRect;
  1592.         Fixed    scaleFactor;
  1593.         
  1594.         drawRect = (**proxyHandle).picFrame;
  1595.         
  1596.         // compute aspect ratio preserving scale
  1597.         if (RectHeight(drawRect) > RectWidth(drawRect))
  1598.             scaleFactor = FixRatio(RectHeight(proxyRect), RectHeight(drawRect));
  1599.         else
  1600.             scaleFactor = FixRatio(RectWidth(proxyRect), RectWidth(drawRect));
  1601.         drawRect.bottom = drawRect.top +
  1602.                     ( FixMul( (RectHeight(drawRect) << 16), scaleFactor) >> 16);
  1603.         drawRect.right = drawRect.left +
  1604.                     ( FixMul( (RectWidth(drawRect) << 16), scaleFactor) >> 16);
  1605.         CenterRect(&drawRect, &proxyRect);
  1606.         
  1607.         // erase the area outside of the picture, but inside of the 
  1608.         // total proxy area, because some pictures will leave whitespace on the edge
  1609.         {
  1610.         RgnHandle    rgn1 = NewRgn();
  1611.         RgnHandle    rgn2 = NewRgn();
  1612.         
  1613.         RectRgn(rgn1, &proxyRect);
  1614.         RectRgn(rgn2, &drawRect);
  1615.         DiffRgn(rgn1, rgn2, rgn1);
  1616.         EraseRgn(rgn1);
  1617.         DisposeRgn(rgn1);
  1618.         DisposeRgn(rgn2);
  1619.         }
  1620.  
  1621.         // finally, we can draw and dispose of the picture
  1622.         DrawPicture(proxyHandle, &drawRect);
  1623.         ReleaseResource((Handle) proxyHandle);
  1624.         
  1625.         }
  1626.     else
  1627.         {
  1628.         EraseRect(&proxyRect);
  1629.         }
  1630.         
  1631. } // DrawPageSliderAndThumb
  1632.  
  1633. // --------------------------------------------------------------------------------------------------------------
  1634. static OSErr    DoDrawingClick(WindowPtr pWindow, WindowDataPtr pData, Point clickPoint, EventRecord *pEvent)
  1635. {
  1636. #pragma unused (pEvent, pWindow)
  1637.  
  1638.     OSErr    anErr = noErr;
  1639.     Point    lastPoint = clickPoint;
  1640.     Point    currentPoint;
  1641.     Fixed    penSize;
  1642.     gxInk    newInk = GXNewInk();
  1643.     gxStyle newStyle = GXNewStyle();
  1644.     gxShape    newShape = GXNewShape(gxPolygonType);
  1645.     long    addPoly[] = {1, 1, 0, 0};
  1646.     
  1647.     // set up the style for the shape
  1648.     GXSetStylePen(newStyle, ff(10));
  1649.     
  1650.     // and the ink for the shape
  1651.     {
  1652.     gxColor    redColor;
  1653.     gxTransferMode mode;
  1654.     
  1655.     // the color
  1656.     redColor.space        = gxRGBSpace;
  1657.     redColor.profile    = nil;
  1658.     redColor.element.rgb.red    = 0xFFFF;
  1659.     redColor.element.rgb.green    = 0x0000;
  1660.     redColor.element.rgb.blue    = 0x0000;
  1661.     GXSetInkColor(newInk, &redColor);
  1662.     
  1663.     // the transfer mode
  1664.     mode.space         = gxHSVSpace;
  1665.     mode.set        = nil;
  1666.     mode.profile    = nil;
  1667.     InitColorMatrix(mode.sourceMatrix);
  1668.     InitColorMatrix(mode.deviceMatrix);
  1669.     InitColorMatrix(mode.resultMatrix);
  1670.     mode.flags        = 0;
  1671.     
  1672.     mode.component[0].mode    = gxCopyMode;
  1673.     mode.component[0].flags    = 0;
  1674.     mode.component[0].sourceMinimum    = 0;
  1675.     mode.component[0].sourceMaximum    = gxColorValue1;
  1676.     mode.component[0].deviceMinimum    = 0;
  1677.     mode.component[0].deviceMaximum    = gxColorValue1;
  1678.     mode.component[0].clampMinimum    = 0;
  1679.     mode.component[0].clampMaximum    = gxColorValue1;
  1680.     mode.component[0].operand        = 0;
  1681.  
  1682.     mode.component[1].mode    = gxCopyMode;
  1683.     mode.component[1].flags    = 0;
  1684.     mode.component[1].sourceMinimum    = 0;
  1685.     mode.component[1].sourceMaximum    = gxColorValue1;
  1686.     mode.component[1].deviceMinimum    = 0;
  1687.     mode.component[1].deviceMaximum    = gxColorValue1;
  1688.     mode.component[1].clampMinimum    = 0;
  1689.     mode.component[1].clampMaximum    = gxColorValue1;
  1690.     mode.component[1].operand        = 0;
  1691.  
  1692.     mode.component[2].mode    = gxNoMode;
  1693.     mode.component[2].flags    = 0;
  1694.     mode.component[2].sourceMinimum    = 0;
  1695.     mode.component[2].sourceMaximum    = gxColorValue1;
  1696.     mode.component[2].deviceMinimum    = 0;
  1697.     mode.component[2].deviceMaximum    = gxColorValue1;
  1698.     mode.component[2].clampMinimum    = 0;
  1699.     mode.component[2].clampMaximum    = gxColorValue1;
  1700.     mode.component[2].operand        = 0;
  1701.     GXSetInkTransfer(newInk, &mode);
  1702.     }
  1703.     
  1704.     // set the style and ink of the shape
  1705.     GXSetShapeStyle(newShape, newStyle);
  1706.     GXSetShapeInk(newShape, newInk);
  1707.     GXSetShapeFill(newShape, gxOpenFrameFill);
  1708.     
  1709.     // initialize the first point in the shape
  1710.     addPoly[2] = ff(lastPoint.h);
  1711.     addPoly[3] = ff(lastPoint.v);
  1712.     GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1713.  
  1714.     // determine the amount we require the mouse to move before adding a new point
  1715.     penSize = FixedDivide(GXGetStylePen(newStyle), ff(2));
  1716.     if (penSize < ff(1))
  1717.         penSize = ff(1);
  1718.  
  1719.     do
  1720.         {
  1721.         GetMouse(¤tPoint);
  1722.         if     (
  1723.             (ff(ABS(currentPoint.h - lastPoint.h)) > penSize) ||
  1724.             (ff(ABS(currentPoint.v - lastPoint.v)) > penSize)
  1725.             )
  1726.             {
  1727.             // add the new point to the new shape
  1728.             lastPoint = currentPoint;
  1729.             addPoly[2] = ff(lastPoint.h);
  1730.             addPoly[3] = ff(lastPoint.v);
  1731.             GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1732.             GXDrawShape(newShape);
  1733.             }
  1734.         } while (StillDown());
  1735.     
  1736.     {
  1737.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  1738.     Fixed            shapeScale = FixedDivide(ff(1), zoomFactor);
  1739.     gxRectangle        pageSize, paperSize;
  1740.         
  1741.     // offset the shape by the scroll bars & margins
  1742.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1743.     GXMoveShape(newShape, 
  1744.                 ff(GetControlValue(pData->hScroll)) + FixedMultiply(paperSize.left, zoomFactor),
  1745.                 ff(GetControlValue(pData->vScroll)) + FixedMultiply(paperSize.top, zoomFactor) );
  1746.  
  1747.     // scale the shape to the current scale factor
  1748.     GXScaleShape(newShape, shapeScale, shapeScale, 0, 0 );
  1749.     GXSetShapePen(newShape, FixedMultiply(GXGetShapePen(newShape), shapeScale) );
  1750.     }
  1751.     
  1752.     // add shape to the page
  1753.     {
  1754.     gxShape        annotationShape = (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  1755.     
  1756.     if (!annotationShape)
  1757.         {
  1758.         annotationShape = GXNewShape(gxPictureType);
  1759.         (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1] = annotationShape;
  1760.         }
  1761.     if (annotationShape)
  1762.         GXSetPictureParts(annotationShape, 0, 0, 1, &newShape, nil, nil, nil);
  1763.     }
  1764.  
  1765.     // all done with our copies of the shape, style, and ink    
  1766.     GXDisposeShape(newShape);
  1767.     GXDisposeStyle(newStyle);
  1768.     GXDisposeInk(newInk);
  1769.     
  1770.     // we've touched the file
  1771.     pData->changed = true;
  1772.     
  1773.     return(anErr);
  1774.     
  1775. } // DoDrawingClick
  1776.  
  1777. // --------------------------------------------------------------------------------------------------------------
  1778.  
  1779. // Handle update/activate events behind Standard File
  1780. static pascal Boolean SaveDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
  1781.                                       short *itemHit, void *myDataPtr)
  1782. {
  1783.     #pragma unused(myDataPtr)
  1784.  
  1785.     if (StdFilterProc(theDialog, theEvent, itemHit))
  1786.         return true;
  1787.  
  1788.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  1789.     // drastically changing how the system handles the menu bar during our alert)
  1790.     if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
  1791.         {
  1792.         HandleEvent(theEvent);
  1793.         }
  1794.  
  1795.     return false;
  1796.  
  1797. } // SaveDialogFilter
  1798.  
  1799. #if GENERATINGCFM
  1800.     static RoutineDescriptor gSaveDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, SaveDialogFilter);
  1801.     static ModalFilterYDUPP gSaveDialogFilter = &gSaveDialogFilterRD;
  1802. #else
  1803.     static ModalFilterYDUPP gSaveDialogFilter = NewModalFilterYDProc(SaveDialogFilter);
  1804. #endif
  1805.  
  1806. // --------------------------------------------------------------------------------------------------------------
  1807. #define kLoadAnnotations    true
  1808. #define kSaveAnnotations    false
  1809.  
  1810. static OSErr    LoadOrSaveAnnotations(WindowDataPtr pData, Boolean load)
  1811. {
  1812.     OSErr                anErr = noErr;
  1813.     short                i;
  1814.     short                oldResFile = CurResFile();
  1815.     userSpool             block;
  1816.     
  1817.     block.spool.spoolProcedure = gHandleSpoolProc;
  1818.     
  1819.     UseResFile(((GXDataPtr)pData)->printFileRefNum);
  1820.     for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1821.         {
  1822.         gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1823.         Handle    annotationHandle;
  1824.         
  1825.         block.spool.buffer = nil;
  1826.         block.spool.bufferSize = 0;
  1827.         if (load)
  1828.             {
  1829.             // load annotation, if any
  1830.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1831.             if (annotationHandle)
  1832.                 {
  1833.                 block.data = annotationHandle;
  1834.                 annotation = GXUnflattenShape(&block.spool, 0, nil);
  1835.                 ReleaseResource(annotationHandle);
  1836.                 }
  1837.             else
  1838.                 {
  1839.                 annotation = nil;
  1840.                 }
  1841.             }
  1842.         else
  1843.             {
  1844.             // remove old annotation
  1845.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1846.             if (annotationHandle)
  1847.                 RemoveResource(annotationHandle);
  1848.                 
  1849.             // add new annotation
  1850.             if (annotation)
  1851.                 {
  1852.                 block.spool.spoolProcedure = gHandleSpoolProc;
  1853.                 block.spool.buffer = nil;
  1854.                 block.spool.bufferSize = 0;
  1855.                 GXFlattenShape(annotation, 0, &block.spool);
  1856.                 annotationHandle = (Handle) block.data;
  1857.                 if (annotationHandle)
  1858.                     {
  1859.                     AddResource(annotationHandle, kAnnotationType, kAnnotationBaseID + i-1, "\p");
  1860.                     ReleaseResource(annotationHandle);
  1861.                     }
  1862.                 }
  1863.             }
  1864.             
  1865.         (*((GXDataPtr)pData)->pageAnnotations)[i] = annotation;
  1866.         }
  1867.     UpdateResFile(CurResFile());
  1868.     UseResFile(oldResFile);
  1869.     
  1870.     return(anErr);
  1871.     
  1872. } // LoadOrSaveAnnotations
  1873.  
  1874. // --------------------------------------------------------------------------------------------------------------
  1875. static OSErr    GXSaveAs(WindowPtr pWindow, WindowDataPtr pData)
  1876. {
  1877.     OSErr                anErr = noErr;
  1878.     Boolean                replacing;
  1879.     FSSpec                fileSpec;
  1880.     NavReplyRecord        navReply;
  1881.     
  1882.     // ask where and how to save this document
  1883.     {
  1884.     Str255    defaultName;
  1885.     Point    where = {-1, -1};
  1886.     
  1887.     // setup for the call
  1888.     GetWTitle(pWindow, defaultName);
  1889.     SetCursor(&qd.arrow);
  1890.     
  1891.     // find out where the user wants the file
  1892.     if (gMachineInfo.haveNavigationServices)
  1893.         {                
  1894.         anErr = SaveFileDialog(defaultName, pData->originalFileType, 'ttxt', MyEventProc, &fileSpec, NULL, &replacing, &navReply);
  1895.         if ( anErr == userCanceledErr)
  1896.             anErr = eUserCanceled;
  1897.         }
  1898.     else
  1899.         {
  1900.         StandardFileReply    sfReply;
  1901.     
  1902.         // find out where the user wants the file
  1903.         CustomPutFile("\p", defaultName, &sfReply, 
  1904.                     sfPutDialogID, where,
  1905.                     nil, gSaveDialogFilter, nil, nil, nil);
  1906.         
  1907.         // map the cancel button into a cancelling error
  1908.         if (!sfReply.sfGood)
  1909.             anErr = eUserCanceled;
  1910.  
  1911.         replacing    = sfReply.sfReplacing;
  1912.         fileSpec    = sfReply.sfFile;
  1913.         }
  1914.     }
  1915.         
  1916.     // can't replace over other types    
  1917.     if (replacing)
  1918.         {
  1919.         FInfo    theInfo;
  1920.         
  1921.         FSpGetFInfo(&fileSpec, &theInfo);
  1922.         
  1923.         if ( 
  1924.             (theInfo.fdType != 'sjob') && 
  1925.             (theInfo.fdType != 'tjob') && 
  1926.             (theInfo.fdType != 'rjob') && 
  1927.             (theInfo.fdType != 'qjob') 
  1928.             )
  1929.             anErr = eDocumentWrongKind;
  1930.         }
  1931.     nrequire(anErr, StandardPutFile);
  1932.         
  1933.     GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, &fileSpec);
  1934.     anErr = GXGetJobError(pData->hPrint);
  1935.  
  1936.  
  1937.     // FALL THROUGH EXCEPTION HANDLING
  1938. StandardPutFile:
  1939.  
  1940.     // if everything went okay
  1941.     if (anErr == noErr)
  1942.         {
  1943.         // update the window title 
  1944.         SetWTitle(pWindow, fileSpec.name);
  1945.     
  1946.         // save new location
  1947.         BlockMoveData(&fileSpec, &pData->fileSpec, sizeof(FSSpec));
  1948.  
  1949.         // update the refNum
  1950.         ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  1951.         
  1952.         // and read in the current page
  1953.         anErr = GetCurrentPage((GXDataPtr) pData, true);
  1954.         }
  1955.         
  1956. // Return eUserCanceled so we can avoid closing/quitting if they cancel the SF dialog
  1957. //    // don't propagate this error
  1958. //    if (anErr == eUserCanceled)
  1959. //        anErr = noErr;
  1960.  
  1961.     if (gMachineInfo.haveNavigationServices)
  1962.         {
  1963.         CompleteSave(&fileSpec, &navReply);
  1964.         }
  1965.  
  1966.     return anErr;
  1967.     
  1968. } // GXSaveAs
  1969.  
  1970. // --------------------------------------------------------------------------------------------------------------
  1971. // OOP INTERFACE ROUTINES
  1972. // --------------------------------------------------------------------------------------------------------------
  1973.  
  1974. static OSErr    GXCloseWindow(WindowPtr pWindow, WindowDataPtr pData)
  1975. {
  1976. #pragma unused (pWindow)
  1977.  
  1978.     if (((GXDataPtr)pData)->pageAnnotations)
  1979.         {
  1980.         short    i;
  1981.         
  1982.         for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1983.             {
  1984.             gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1985.             
  1986.             if (annotation)
  1987.                 GXDisposeShape(annotation);
  1988.             }
  1989.         DisposeHandle((Handle) (((GXDataPtr)pData)->pageAnnotations) );
  1990.         ((GXDataPtr)pData)->pageAnnotations = nil;
  1991.         }
  1992.     
  1993.     if (((GXDataPtr)pData)->currentSelectionShape)
  1994.         {
  1995.         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1996.         ((GXDataPtr)pData)->currentSelectionShape = nil;
  1997.         }
  1998.                         
  1999.     if (((GXDataPtr)pData)->currentPageShape)
  2000.         {
  2001.         GXDisposeShape(((GXDataPtr)pData)->currentPageShape);
  2002.         ((GXDataPtr)pData)->currentPageShape = nil;
  2003.         }
  2004.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  2005.  
  2006.     GXDisposeViewPort( ((GXDataPtr)pData)->parentViewPort);
  2007.     GXDisposeViewPort( ((GXDataPtr)pData)->childViewPort);
  2008.  
  2009.     return(noErr);
  2010.     
  2011. } // GXCloseWindow
  2012.  
  2013. // --------------------------------------------------------------------------------------------------------------
  2014.  
  2015. static OSErr    GXUpdateWindow(WindowPtr pWindow, WindowDataPtr pData)
  2016. {
  2017.     gxGraphicsError        anErr = noErr;    
  2018.  
  2019.     // draw informational area to the left of the horizontal scroll bar
  2020.     {
  2021.     FontInfo    theInfo;
  2022.     Rect        infoArea;
  2023.     RgnHandle    oldClip = NewRgn();
  2024.     Handle        theString;
  2025.     long        theStringSize;
  2026.     
  2027.     // save old clip and clip to the label area
  2028.     GetClip(oldClip);
  2029.     infoArea.left = 0;
  2030.     infoArea.right = pData->hScrollOffset-1;
  2031.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  2032.     infoArea.top = infoArea.bottom - kScrollBarSize;
  2033.     ClipRect(&infoArea);
  2034.         
  2035.     // draw the label
  2036.     TextFont(applFont);
  2037.     TextSize(9);
  2038.     GetFontInfo(&theInfo);
  2039.     theString = GetResource('LSTR', kLabelString);
  2040.     if (theString)
  2041.         {
  2042.         Handle    inString = NewHandle(sizeof(Str255));
  2043.         Str255    newString;
  2044.         Rect    labelArea = infoArea;
  2045.         
  2046.         // erase any old string we had there
  2047.         labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  2048.         if (((GXDataPtr)pData)->numberOfPages > 1)
  2049.             labelArea.left += kPageControlsWidth;        
  2050.         EraseRect(&labelArea);
  2051.         
  2052.         // current page label
  2053.         NumToString(((GXDataPtr)pData)->currentPage, newString);
  2054.         SetHandleSize(inString, newString[0]);
  2055.         BlockMoveData(&newString[1], *inString, newString[0]);
  2056.         ReplaceText(theString, inString, "\p^0");
  2057.  
  2058.         // total page count label
  2059.         NumToString(((GXDataPtr)pData)->numberOfPages, newString);
  2060.         SetHandleSize(inString, newString[0]);
  2061.         BlockMoveData(&newString[1], *inString, newString[0]);
  2062.         ReplaceText(theString, inString, "\p^1");
  2063.  
  2064.         // scale factor label
  2065.         NumToString(FixedToInt( FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(100)) ), newString);
  2066.         SetHandleSize(inString, newString[0]);
  2067.         BlockMoveData(&newString[1], *inString, newString[0]);
  2068.         ReplaceText(theString, inString, "\p^2");
  2069.  
  2070.         // done with replace string content
  2071.         DisposeHandle(inString);
  2072.         
  2073.         // draw the label
  2074.         HLock(theString);
  2075.         theStringSize = GetHandleSize(theString);
  2076.         MoveTo(labelArea.left + ((labelArea.right - labelArea.left) >> 1) - (TextWidth(*theString, 0, theStringSize) >> 1), 
  2077.                 labelArea.top + ((labelArea.bottom - labelArea.top)>>1) + ((theInfo.ascent + theInfo.descent) >> 1) - theInfo.descent);
  2078.         DrawText(*theString, 0, theStringSize);
  2079.         ReleaseResource(theString);
  2080.         }
  2081.         
  2082.     // draw the current tool
  2083.         {
  2084.         Rect        toolArea = infoArea;
  2085.         CIconHandle    icon;
  2086.         
  2087.         toolArea.left = toolArea.right - kToolControlWidth;
  2088.         toolArea.right = toolArea.left + 32;
  2089.         toolArea.bottom = toolArea.top + 32;
  2090.         EraseRect(&toolArea);
  2091.         OffsetRect(&toolArea, -8, -8);
  2092.         
  2093.         icon = GetCIcon(kIconBase + ((GXDataPtr)pData)->contentClickMode);
  2094.         if (icon)
  2095.             {
  2096.             PlotCIconHandle(&toolArea, kAlignAbsoluteCenter, ttNone, icon);
  2097.             DisposeCIcon(icon);
  2098.             }
  2099.         }
  2100.  
  2101.     // draw the zoom controls
  2102.         {
  2103.         Rect    zoomArea = infoArea;
  2104.         zoomArea.left = zoomArea.right - kZoomControlsWidth - kToolControlWidth;
  2105.         zoomArea.right = zoomArea.left + 32;
  2106.         zoomArea.bottom = zoomArea.top + 32;
  2107.         
  2108.         PlotIconID(&zoomArea, ttNone, ttNone, kZoomControlPlain);
  2109.         }
  2110.                 
  2111.     // draw the left/right/page arrows
  2112.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2113.         {
  2114.         Rect    arrowsRect;
  2115.         
  2116.         // erase any old arrow bits, including around the edges of the icon
  2117.         // needed when the window resizes
  2118.         arrowsRect = infoArea;
  2119.         arrowsRect.bottom = arrowsRect.top + 32;
  2120.         arrowsRect.right = arrowsRect.left + 34;
  2121.         EraseRect(&arrowsRect);
  2122.         
  2123.         // then draw the new arrows
  2124.         arrowsRect.left = infoArea.left + 2;
  2125.         arrowsRect.top = infoArea.top + 2;
  2126.         arrowsRect.right = arrowsRect.left + kPageControlsWidth;
  2127.         arrowsRect.bottom = arrowsRect.top + 32;
  2128.         PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2129.         }
  2130.     
  2131.     // frame the area
  2132.     MoveTo(infoArea.left, infoArea.top);
  2133.     LineTo(infoArea.right, infoArea.top);
  2134.  
  2135.     // restore old clip value
  2136.     SetClip(oldClip);
  2137.     DisposeRgn(oldClip);
  2138.     }
  2139.  
  2140.  
  2141.     // then draw the page shape and things around it
  2142.     {
  2143.     gxRectangle            pageSize, paperSize;    
  2144.     gxShape                tempShape, pageShape;
  2145.     gxMapping            thisMapping;
  2146.  
  2147.     // clip to the content area
  2148.     paperSize.left         = ff(pData->contentRect.left);
  2149.     paperSize.top         = ff(pData->contentRect.top);
  2150.     paperSize.right     = ff(pData->contentRect.right);
  2151.     paperSize.bottom     = ff(pData->contentRect.bottom);
  2152.     tempShape = GXNewRectangle(&paperSize);
  2153.     GXSetViewPortClip(((GXDataPtr)pData)->childViewPort, tempShape);
  2154.     GXDisposeShape(tempShape);
  2155.     
  2156.     // get the paper sizes, account for zoom factor
  2157.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2158.     pageSize.left         = FixedMultiply(pageSize.left, ((GXDataPtr)pData)->zoomFactor);
  2159.     pageSize.right         = FixedMultiply(pageSize.right, ((GXDataPtr)pData)->zoomFactor);
  2160.     pageSize.top         = FixedMultiply(pageSize.top, ((GXDataPtr)pData)->zoomFactor);
  2161.     pageSize.bottom     = FixedMultiply(pageSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2162.     paperSize.left         = FixedMultiply(paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  2163.     paperSize.right     = FixedMultiply(paperSize.right, ((GXDataPtr)pData)->zoomFactor);
  2164.     paperSize.top         = FixedMultiply(paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  2165.     paperSize.bottom     = FixedMultiply(paperSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2166.     
  2167.     // offset by the scrolling amount    
  2168.     ResetMapping(&thisMapping);
  2169.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2170.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2171.  
  2172.     // make the paper shape
  2173.     tempShape = GXNewShape(gxFullType);
  2174.     GXSetTransformViewPorts(GXGetShapeTransform(tempShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2175.     GXSetShapeFill(tempShape, gxEvenOddFill);
  2176.     GXSetShapeMapping(tempShape, &thisMapping);
  2177.     
  2178.     // make the page shape
  2179.     pageShape = GXNewRectangle(&pageSize);
  2180.     GXSetTransformViewPorts(GXGetShapeTransform(pageShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2181.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2182.     GXSetShapeMapping(pageShape, &thisMapping);
  2183.     
  2184.     // remove the page shape from the paper shape
  2185.     GXDifferenceShape(tempShape, pageShape);
  2186.  
  2187.     // draw the paper shape, dispose of it
  2188.     SetShapeGreyColorLevel(tempShape, 0xD000);    /* Set up light gray background */
  2189.     GXDrawShape(tempShape);
  2190.     GXDisposeShape(tempShape);
  2191.     
  2192.     // draw white on the page shape
  2193.     SetShapeGreyColorLevel(pageShape, 0xFFFF);    /* Set up white page */
  2194.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2195.     GXDrawShape(pageShape);
  2196.     
  2197.     // frame the page shape
  2198.     SetShapeGreyColorLevel(pageShape, 0x8000);    /* Set up medium gray frame */
  2199.     GXSetShapeFill(pageShape, gxClosedFrameFill);
  2200.     GXDrawShape(pageShape);
  2201.     
  2202.     // draw the scroll bars and grow box now to give a nice appearence
  2203.     DrawControls(pWindow);
  2204.     DrawGrowIcon(pWindow);
  2205.  
  2206.     // draw the page data itself, clipped to the page
  2207.  
  2208.     {
  2209.     gxMapping    oldMapping, flipMapping;
  2210.     
  2211.     // get the page shape's old mapping, and make a copy to work with
  2212.     GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &oldMapping);
  2213.  
  2214.     // run the clip through the inverse of the shape mapping to scale it properly
  2215.     GXInsetShape(pageShape, ff(1));
  2216.     ScaleMapping(&oldMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2217.     InvertMapping(&flipMapping, &oldMapping);
  2218.     GXMapShape(pageShape, &flipMapping);
  2219.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2220.     GXSetShapeClip( ((GXDataPtr)pData)->currentPageShape, pageShape);
  2221.     
  2222.     // move the shape into position by offseting the viewPort
  2223.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2224.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2225.     ScaleMapping(&thisMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2226.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2227.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2228.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2229.  
  2230.     /*
  2231.      *    Bracket the call to DrawShape with UseResFile, so that we put the
  2232.      *    document's resfile on top, allowing the translator (for QDShapes)
  2233.      *    to see our embedded fonts (if any) first.
  2234.      */
  2235.     {    short oldResFile = CurResFile();
  2236.     
  2237.         UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2238.         GXDrawShape( ((GXDataPtr)pData)->currentPageShape);
  2239.         UseResFile(oldResFile);
  2240.     }
  2241.  
  2242.     
  2243.     // Draw the selection, if any
  2244.     {
  2245.     gxShape    selectionShape =  ((GXDataPtr)pData)->currentSelectionShape;
  2246.     gxShape    highlight;
  2247.     
  2248.     if (selectionShape)
  2249.         {
  2250.         
  2251.         // better be a layout shape to get hilights
  2252.         GXSetShapeType(selectionShape, gxLayoutType);
  2253.         
  2254.         // get the highlight
  2255.         highlight = GetCurrentSelectionHighlight(pData, true);
  2256.         GXDrawShape(highlight);
  2257.         GXDisposeShape(highlight);                        
  2258.         }
  2259.     }
  2260.  
  2261.     // Draw the overlay, if any
  2262.     {
  2263.     gxShape    annotationShape =  (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  2264.     
  2265.     if (annotationShape)
  2266.         {
  2267.         GXSetShapeViewPorts(annotationShape, 1, &((GXDataPtr)pData)->childViewPort);
  2268.         GXDrawShape(annotationShape);
  2269.         }    
  2270.     }
  2271.  
  2272.     // restore viewPort's mapping (so we don't use it again next time)
  2273.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2274.  
  2275.     
  2276.     }
  2277.     
  2278.     // done with the page shape
  2279.     GXDisposeShape(pageShape);
  2280.  
  2281.     DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2282.  
  2283.     GXGetGraphicsError(&anErr);
  2284.     }
  2285.     
  2286.     return(anErr);
  2287.     
  2288. } // GXUpdateWindow
  2289.  
  2290. // --------------------------------------------------------------------------------------------------------------
  2291.  
  2292. static OSErr    GXContentClick(WindowPtr pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2293. {
  2294.     OSErr            anErr = noErr;
  2295.     Point            clickPoint = pEvent->where;
  2296.     Rect            infoArea, labelArea, toolArea;
  2297.     Rect            zoomOutRect, zoomInRect, zoomsRect;
  2298.     RgnHandle        oldClip = NewRgn();
  2299.     Boolean            somethingHit = false;
  2300.     
  2301.     // convert to local space, calculate clickable areas    
  2302.     GlobalToLocal(&clickPoint);
  2303.     infoArea.left = 0;
  2304.     infoArea.right = pData->hScrollOffset-1;
  2305.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  2306.     infoArea.top = infoArea.bottom - kScrollBarSize;
  2307.  
  2308.     // clip to the info area
  2309.     GetClip(oldClip);
  2310.     ClipRect(&infoArea);
  2311.  
  2312.     // label area
  2313.     labelArea = infoArea;
  2314.     labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  2315.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2316.         labelArea.left += kPageControlsWidth;        
  2317.  
  2318.     // the tool pop up
  2319.     toolArea = infoArea;
  2320.     toolArea.left = toolArea.right - kToolControlWidth;
  2321.     
  2322.     // calculate the zoom in/out rects
  2323.     zoomInRect = infoArea;
  2324.     zoomInRect.right -= kToolControlWidth;
  2325.     zoomInRect.left = zoomInRect.right - 13;
  2326.     zoomOutRect = zoomInRect;
  2327.     OffsetRect(&zoomOutRect, -13, 0);
  2328.     zoomsRect = zoomOutRect;
  2329.     zoomsRect.bottom = zoomsRect.top + 32;
  2330.     zoomsRect.right = zoomsRect.left + 32;
  2331.  
  2332.     // deal with zoom in/out clicks
  2333.     if (TrackIn(&zoomInRect, clickPoint, &zoomsRect, kZoomControlRight, kZoomControlPlain))
  2334.         {
  2335.         somethingHit = true;
  2336.         SetZoom(pWindow, pData, FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2337.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2338.         }
  2339.  
  2340.     if (TrackIn(&zoomOutRect, clickPoint, &zoomsRect, kZoomControlLeft, kZoomControlPlain))
  2341.         {
  2342.         somethingHit = true;
  2343.         SetZoom(pWindow, pData, FixedDivide(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2344.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2345.         }
  2346.  
  2347.     // deal with the options pop up
  2348.     if (PtInRect(clickPoint, &labelArea))
  2349.         {
  2350.         MenuHandle    popupMenu = GetMenu(kGXPopUpMenu);
  2351.         short        selectedItem;
  2352.         TextState    textState;
  2353.         Point        popPoint;
  2354.         char        bulletString[3];
  2355.         
  2356.         // figure out where to display the pop up
  2357.         popPoint.v = labelArea.top;
  2358.         popPoint.h = labelArea.left;
  2359.         LocalToGlobal(&popPoint);
  2360.  
  2361.         somethingHit = true;
  2362.         GetIntlTokenChar(tokenCenterDot, FontToScript(applFont), bulletString);
  2363.         
  2364.         // set up menu to be small sized
  2365.         TextFont(applFont);
  2366.         TextSize(9);
  2367.         DoUseWFont(&textState, pWindow, true);
  2368.         
  2369.         // set up the menu for selected items
  2370.         SetItemMark(popupMenu, iDontShowMargins, (((GXDataPtr)pData)->dontShowMargins) ? bulletString[1] : noMark);
  2371.         {
  2372.         ZoomTableEntry *pEntry = &gZoomTable[0];
  2373.         
  2374.         while (pEntry->menuItem != 0)
  2375.             {
  2376.             SetItemMark(popupMenu, pEntry->menuItem, (((GXDataPtr)pData)->zoomFactor == pEntry->zoomFactor) ? bulletString[1] : noMark);
  2377.             pEntry++;
  2378.             }
  2379.         }
  2380.         
  2381.         // conduct the menu
  2382.         InsertMenu(popupMenu, -1);
  2383.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, CountMenuItems(popupMenu)+1) & 0xFFFF;
  2384.  
  2385.         // restore menu sizes
  2386.         DoUseWFont(&textState, nil, false);
  2387.         DeleteMenu(kGXPopUpMenu);
  2388.         
  2389.         switch (selectedItem)
  2390.             {                
  2391.             // toggle show/hide margins
  2392.             case iDontShowMargins:
  2393.                 // flip the boolean
  2394.                 ((GXDataPtr)pData)->dontShowMargins = 1 - ((GXDataPtr)pData)->dontShowMargins;
  2395.                 
  2396.                 // force update and recalc the size of window
  2397.                 InvalRect(&GetWindowPort(pWindow)->portRect);
  2398.                 AdjustScrollBars(pWindow, true, true, nil);
  2399.                 break;
  2400.  
  2401.             // scale graphics to fit the window
  2402.             case iScaleToFit:
  2403.                 {
  2404.                 gxRectangle        pageSize, paperSize;
  2405.                 Fixed            horizScale, vertScale;
  2406.                 GrafPtr            pPort = (GrafPtr)GetWindowPort(pWindow);
  2407.                 
  2408.                 GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2409.                 
  2410.                 pageSize.left = pageSize.top = 0;
  2411.                 pageSize.right = ff(pPort->portRect.right - kScrollBarSize);
  2412.                 pageSize.bottom = ff(pPort->portRect.bottom - kScrollBarSize);
  2413.                 
  2414.                 horizScale = FixedDivide(pageSize.right - pageSize.left, paperSize.right - paperSize.left);
  2415.                 vertScale = FixedDivide(pageSize.bottom - pageSize.top, paperSize.bottom - paperSize.top);
  2416.                 if (horizScale > vertScale)
  2417.                     SetZoom(pWindow, pData, vertScale);
  2418.                 else
  2419.                     SetZoom(pWindow, pData, horizScale);
  2420.                 }
  2421.                 break;
  2422.                 
  2423.             // absolute set scale cases
  2424.             default:
  2425.                 {
  2426.                 ZoomTableEntry *pEntry = &gZoomTable[0];
  2427.                 
  2428.                 while (pEntry->menuItem != 0)
  2429.                     {
  2430.                     if (selectedItem == pEntry->menuItem)
  2431.                         SetZoom(pWindow, pData, pEntry->zoomFactor);
  2432.                     pEntry++;
  2433.                     }
  2434.                 }
  2435.                 break;
  2436.             }
  2437.             
  2438.         }
  2439.         
  2440.     // deal with the tool pop up
  2441.     if (PtInRect(clickPoint, &toolArea))
  2442.         {
  2443.         MenuHandle    popupMenu = GetMenu(kGXToolMenu);
  2444.         short        selectedItem;
  2445.         Point        popPoint;
  2446.         short        i, numItems;
  2447.         
  2448.         // figure out where to display the pop up
  2449.         popPoint.v = toolArea.top;
  2450.         popPoint.h = toolArea.left;
  2451.         LocalToGlobal(&popPoint);
  2452.  
  2453.         // we've processed the mouse click
  2454.         somethingHit = true;
  2455.         
  2456.         // select our current item in the menu
  2457.         numItems = CountMenuItems(popupMenu);
  2458.         for (i = 1; i <= numItems; ++i)
  2459.             MacCheckMenuItem(popupMenu, i, (i == ((GXDataPtr)pData)->contentClickMode) );
  2460.         
  2461.         // conduct the menu
  2462.         InsertMenu(popupMenu, -1);
  2463.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, numItems+1) & 0xFFFF;
  2464.         DeleteMenu(kGXPopUpMenu);
  2465.  
  2466.         // remember the item selected
  2467.         if (selectedItem != 0)
  2468.             ((GXDataPtr)pData)->contentClickMode = selectedItem;
  2469.             
  2470.         // invalidation the tool picture
  2471.         InvalRect(&toolArea);
  2472.         
  2473.         if (selectedItem != kSelectionTool)
  2474.             {
  2475.             // erase the old selection
  2476.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2477.     
  2478.             // clear the selection
  2479.             ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2480.             ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2481.             ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2482.             ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2483.     
  2484.             // draw the new selection
  2485.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2486.             }
  2487.         }
  2488.         
  2489.     // deal with clicks in page controls
  2490.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2491.         {
  2492.         Rect    leftArrowRect, rightArrowRect, arrowsRect;
  2493.         Rect    gotoPageRect;
  2494.         
  2495.         // calculate the minus one page arrow        
  2496.         leftArrowRect.top         = infoArea.top + 2;
  2497.         leftArrowRect.bottom     = leftArrowRect.top + 32;
  2498.         leftArrowRect.left         = infoArea.left + 2;
  2499.         leftArrowRect.right     = leftArrowRect.left + 11;
  2500.                 
  2501.         // calculate the go to a particular page rect        
  2502.         gotoPageRect = leftArrowRect;
  2503.         OffsetRect(&gotoPageRect, 11, 0);
  2504.         gotoPageRect.right --;
  2505.  
  2506.         // calculate the plus one page arrow        
  2507.         rightArrowRect = gotoPageRect;
  2508.         OffsetRect(&rightArrowRect, 10, 0);
  2509.         
  2510.         // calculate sum of all areas
  2511.         arrowsRect = leftArrowRect;
  2512.         arrowsRect.left     = infoArea.left + 2;
  2513.         arrowsRect.right     = arrowsRect.left + kPageControlsWidth;
  2514.                     
  2515.         if (TrackIn(&leftArrowRect, clickPoint, &arrowsRect, kPageControlLeft, kPageControlPlain))
  2516.             {
  2517.             somethingHit = true;
  2518.             if (((GXDataPtr)pData)->currentPage > 1) 
  2519.                 anErr = GXCommand(pWindow, pData, cPreviousPage, 0);
  2520.             else
  2521.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2522.             }
  2523.  
  2524.         if (TrackIn(&rightArrowRect, clickPoint, &arrowsRect, kPageControlRight, kPageControlPlain))
  2525.             {
  2526.             somethingHit = true;
  2527.             if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2528.                 anErr = GXCommand(pWindow, pData, cNextPage, 0);
  2529.             else
  2530.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2531.             }
  2532.             
  2533.         if (PtInRect(clickPoint, &gotoPageRect))
  2534.             {
  2535.             unsigned long    actualTicks;
  2536.             
  2537.             somethingHit = true;
  2538.             // pause, then check if the mouse is still down
  2539.             Delay(20, &actualTicks);
  2540.             
  2541.             // if still down, track preview window
  2542.             if (StillDown())
  2543.                 {
  2544.                 WindowPtr    popWindow;
  2545.                 Rect        windowRect;
  2546.                 short        oldResFile = CurResFile();
  2547.                 
  2548.                 // put the print file on top
  2549.                 UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2550.                 
  2551.                 // figure out where to place the pop up window, and then make it
  2552.                 windowRect.bottom     = arrowsRect.top - 2;
  2553.                 windowRect.left        = 2;
  2554.                 if (Count1Resources(kProxyType) > 0)
  2555.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightLarge;
  2556.                 else
  2557.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightSmall;
  2558.                 windowRect.right     = windowRect.left + kScrollAreaWidth + kPageControlsWidth + kZoomControlsWidth + kToolControlWidth - 4;
  2559.                     
  2560.                 LocalToGlobal(&TopLeft(windowRect));                
  2561.                 LocalToGlobal(&BotRight(windowRect));                
  2562.                 
  2563.                 popWindow = NewCWindow(nil, &windowRect, "\p", true, plainDBox, (WindowPtr)-1, false, 0);
  2564.                 if (popWindow)
  2565.                     {            
  2566.                     long    oldValue = ((GXDataPtr)pData)->currentPage;
  2567.                     long    newValue = oldValue;
  2568.                     GrafPtr    popPort = (GrafPtr)GetWindowPort(popWindow);
  2569.                     
  2570.                     // draw initial location of the value
  2571.                     SetPort(popPort);
  2572.                     DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2573.                                         
  2574.                     // track the mouse, updating the value as we go
  2575.                     while (StillDown())
  2576.                         {
  2577.                         GetMouse(&clickPoint);
  2578.                         if (PtInRect(clickPoint, &popPort->portRect))
  2579.                             {
  2580.                             newValue =     clickPoint.h
  2581.                                             *
  2582.                                         ((GXDataPtr)pData)->numberOfPages
  2583.                                             /
  2584.                                         (popPort->portRect.right - popPort->portRect.left) 
  2585.                                             + 1;
  2586.                                         
  2587.                             if (oldValue != newValue)
  2588.                                 {
  2589.                                 oldValue = newValue;
  2590.                                 DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2591.                                 }
  2592.                             }
  2593.                         }
  2594.                         
  2595.                     // and done with the pop up window, return to main window
  2596.                     DisposeWindow(popWindow);
  2597.                     SetPort((GrafPtr)GetWindowPort(pWindow));
  2598.                     
  2599.                     // if we changed the value, make it so
  2600.                     if (newValue != ((GXDataPtr)pData)->currentPage)
  2601.                         {
  2602.                         ((GXDataPtr)pData)->currentPage = newValue;
  2603.                         anErr = GetCurrentPage((GXDataPtr) pData, true);
  2604.                         InvalRect(&GetWindowPort(pWindow)->portRect);
  2605.                         }
  2606.                     }
  2607.                     
  2608.                 // restore resource chain
  2609.                 UseResFile(oldResFile);
  2610.                 }
  2611.             else
  2612.                 {
  2613.                 // otherwise, do the goto dialog box
  2614.                 anErr = GXCommand(pWindow, pData, cGotoPage, 0);
  2615.                 }
  2616.                 
  2617.             } // if (click in goto page area)
  2618.             
  2619.         } // if (> 1 page)
  2620.  
  2621.     // restore clip
  2622.     SetClip(oldClip);
  2623.     DisposeRgn(oldClip);
  2624.     
  2625.     // nothing matched so far, deal with selecting the contents
  2626.     if (!somethingHit)
  2627.         {
  2628.         Rect    selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  2629.         
  2630.         
  2631.         OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  2632.         if ( (gMachineInfo.haveDragMgr) && (PtInRect(clickPoint, &selectionRect)) )
  2633.             {
  2634.             ((GXDataPtr)pData)->tempDragShape = nil;
  2635.             DragAndDropArea(pWindow, pData, pEvent, 
  2636.                                 &selectionRect);
  2637.                 
  2638.                                 
  2639.             if ( ((GXDataPtr)pData)->tempDragShape )
  2640.                 GXDisposeShape( ((GXDataPtr)pData)->tempDragShape );
  2641.             }
  2642.         else
  2643.             {
  2644.             LongRect        docRect;
  2645.             Rect            contentRect;
  2646.             
  2647.             contentRect = GetWindowPort(pWindow)->portRect;
  2648.             contentRect.right -= kScrollBarSize;
  2649.             contentRect.bottom -= kScrollBarSize;
  2650.             
  2651.             if (PtInRect(clickPoint, &contentRect))
  2652.                 {
  2653.                 switch (((GXDataPtr)pData)->contentClickMode)
  2654.                     {
  2655.                     case kSelectionTool:
  2656.                         GXGetDocumentRect(pWindow, pData, &docRect, false);
  2657.                         contentRect.top     = docRect.top;
  2658.                         contentRect.left     = docRect.left;
  2659.                         contentRect.bottom     = docRect.bottom;
  2660.                         contentRect.right     = docRect.right;
  2661.                         
  2662.                         anErr = SelectContents(pWindow, pData, pEvent, 
  2663.                                             &((GXDataPtr)pData)->selectionRectangle, &contentRect, 
  2664.                                             &((GXDataPtr)pData)->patternPhase);
  2665.                 
  2666.                         // existing text selection? clear the highlight
  2667.                         if (((GXDataPtr)pData)->currentSelectionShape)
  2668.                             {
  2669.                             InvalRect(&GetWindowPort(pWindow)->portRect);
  2670.                             
  2671.                             ClearCurrentSelection((GXDataPtr)pData);
  2672.                             }
  2673.                         break;
  2674.  
  2675.                     case kRedMarkerTool:
  2676.                         DoDrawingClick(pWindow, pData, clickPoint, pEvent);
  2677.                         break;
  2678.                         
  2679.                     } // switch (mode)
  2680.                     
  2681.                 } // click in content rect
  2682.             }
  2683.         }
  2684.         
  2685.     return(anErr);
  2686.         
  2687. } // GXContentClick
  2688.  
  2689. // --------------------------------------------------------------------------------------------------------------
  2690.  
  2691. static OSErr    GXAdjustMenus(WindowPtr pWindow, WindowDataPtr pData)
  2692. {
  2693. #pragma unused (pWindow)
  2694.  
  2695.     OSErr anErr = noErr;
  2696.     
  2697.     EnableCommand(cSaveAs);
  2698.  
  2699.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2700.         {
  2701.         if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2702.             EnableCommand(cNextPage);
  2703.             
  2704.         if (((GXDataPtr)pData)->currentPage > 1)
  2705.             EnableCommand(cPreviousPage);
  2706.         
  2707.         EnableCommand(cGotoPage);
  2708.         }
  2709.         
  2710.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle) )
  2711.         EnableCommand(cCopy);
  2712.  
  2713.     {
  2714.     LongRect        docRect;
  2715.     Rect            shortDocRect;
  2716.     
  2717.     // find out the size of the document            
  2718.     GXGetDocumentRect(pWindow, pData, &docRect, false);
  2719.     LongRectToRect(&docRect, &shortDocRect);
  2720.     if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2721.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectNoneCommand);
  2722.     else
  2723.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand);
  2724.     }
  2725.     EnableCommand(cSelectAll);
  2726.     
  2727.     EnableCommand(cFind);
  2728.     if (gFindString[0] != 0)
  2729.         EnableCommand(cFindAgain);
  2730.     
  2731.     return(anErr);
  2732.     
  2733. } // GXAdjustMenus
  2734.  
  2735. // --------------------------------------------------------------------------------------------------------------
  2736.  
  2737. OSErr    GXCommand(WindowPtr pWindow, WindowDataPtr pData, short commandID, long menuResult)
  2738. {
  2739. #pragma unused (menuResult)
  2740.  
  2741.     OSErr    anErr = noErr;
  2742.         
  2743.     switch (commandID)
  2744.         {
  2745.         case cSave:
  2746.             GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, nil);
  2747.             anErr = GXGetJobError(pData->hPrint);
  2748.             if (anErr == noErr)
  2749.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2750.                 
  2751.             // if everything went okay, then clear the changed bit
  2752.             if (anErr == noErr)
  2753.                 pData->changed = false;
  2754.             break;
  2755.             
  2756.         case cSaveAs:
  2757.             anErr = GXSaveAs(pWindow, pData);
  2758.             if (anErr == noErr)
  2759.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2760.  
  2761.             // if everything went okay, then clear the changed bit
  2762.             if (anErr == noErr)
  2763.                 pData->changed = false;
  2764.             break;
  2765.             
  2766.         case cFind:
  2767.             if (ConductFindOrReplaceDialog(kFindWindowID) == cancel)    
  2768.                 break;
  2769.             
  2770.             // start search at top of page
  2771.             ((GXDataPtr)pData)->currentShapeIndex = 0;
  2772.             
  2773.         // fall through from find
  2774.         case cFindAgain:
  2775.             {
  2776.             Boolean    isBackwards = ((gEvent.modifiers & shiftKey) != 0);
  2777.             
  2778.             SetWatchCursor();
  2779.  
  2780.             if (!PerformNextFind(pWindow, pData, gFindString, gCaseSensitive, isBackwards, gWrapAround))
  2781.                 SysBeep(1);
  2782.             else
  2783.                 ScrollFoundShapeIntoView(pWindow, pData);
  2784.                 
  2785.             SetCursor(&qd.arrow);
  2786.             }
  2787.             break;
  2788.  
  2789.         case cCopy:
  2790.             {
  2791.             gxShape            cullShape = GetSelectedShape(pData);
  2792.  
  2793.             if (cullShape)
  2794.                 {
  2795.                 // done with the shape now
  2796.                 ShapeToScrap(cullShape);
  2797.                 GXDisposeShape(cullShape);
  2798.                 }
  2799.             }
  2800.             break;
  2801.         
  2802.         case cSelectAll:
  2803.             {
  2804.             LongRect        docRect;
  2805.             Rect            shortDocRect;
  2806.             
  2807.             // find out the size of the document            
  2808.             GXGetDocumentRect(pWindow, pData, &docRect, false);
  2809.  
  2810.             // erase the old selection
  2811.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2812.             
  2813.             LongRectToRect(&docRect, &shortDocRect);
  2814.             if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2815.                 {
  2816.                 ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2817.                 ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2818.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2819.                 ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2820.                 }
  2821.             else
  2822.                 {
  2823.                 ((GXDataPtr)pData)->selectionRectangle.top         = docRect.top;
  2824.                 ((GXDataPtr)pData)->selectionRectangle.left        = docRect.left;
  2825.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = docRect.bottom;
  2826.                 ((GXDataPtr)pData)->selectionRectangle.right    = docRect.right;
  2827.                 }
  2828.  
  2829.             // draw the new selection
  2830.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2831.             
  2832.             DoAdjustCursor(pWindow, nil);
  2833.  
  2834.             }
  2835.             break;
  2836.  
  2837.         case cPageSetup:
  2838.             DoPageSetup(pWindow);
  2839.             anErr = GetCurrentPage((GXDataPtr) pData, false);
  2840.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2841.             anErr = eActionAlreadyHandled;
  2842.             break;
  2843.             
  2844.         case cNextPage:
  2845.             ((GXDataPtr)pData)->currentPage++;
  2846.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2847.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2848.             if (anErr == noErr)
  2849.                 anErr = eActionAlreadyHandled;
  2850.             break;
  2851.         
  2852.         case cPreviousPage:
  2853.             ((GXDataPtr)pData)->currentPage--;
  2854.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2855.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2856.             if (anErr == noErr)
  2857.                 anErr = eActionAlreadyHandled;
  2858.             break;
  2859.         
  2860.         case cGotoPage:
  2861.             switch (menuResult)
  2862.                 {
  2863.                 case cGotoFirst:
  2864.                     ((GXDataPtr)pData)->currentPage = 1;
  2865.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2866.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2867.                     break;
  2868.  
  2869.                 case cGotoLast:
  2870.                     ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  2871.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2872.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2873.                     break;
  2874.                     
  2875.                 default:
  2876.                     {
  2877.                     DialogPtr    dPtr;
  2878.                     short        hit;
  2879.                     
  2880.                     dPtr = GetNewDialog(kGotoPageDialogID, nil, (WindowPtr)-1);
  2881.                     if (dPtr)
  2882.                         {
  2883.                         short    theType;
  2884.                         Handle    theHandle;
  2885.                         Rect    theRect;
  2886.                         Str255    theString;
  2887.                         
  2888.                         GetDialogItem(dPtr, 4, &theType, &theHandle, &theRect);
  2889.                         NumToString(((GXDataPtr)pData)->currentPage, theString);
  2890.                         SetDialogItemText(theHandle, theString);
  2891.                         SelectDialogItemText(dPtr, 4, 0, 32767);
  2892.  
  2893.                         NumToString(((GXDataPtr)pData)->numberOfPages, theString);
  2894.                         ParamText(theString, "\p", "\p", "\p");
  2895.                         
  2896.                         SetDialogDefaultItem(dPtr, ok);
  2897.                         SetDialogCancelItem(dPtr, cancel);
  2898.                         BeginMovableModal();
  2899.                         
  2900.                         do
  2901.                             {
  2902.                             MovableModalDialog(nil, &hit);
  2903.                             
  2904.                             if (hit == ok)
  2905.                                 {
  2906.                                 long    tempLong;
  2907.                                 
  2908.                                 // convert to a page number, find and report errors
  2909.                                 GetDialogItemText(theHandle, theString);
  2910.                                 StringToNum(theString, &tempLong);
  2911.                                 if (tempLong < 1) 
  2912.                                     {
  2913.                                     SysBeep(1);
  2914.                                     tempLong = 1;
  2915.                                     hit = 0;
  2916.                                     }
  2917.                                 if (tempLong > ((GXDataPtr)pData)->numberOfPages)
  2918.                                     {
  2919.                                     tempLong = ((GXDataPtr)pData)->numberOfPages;
  2920.                                     hit = 0;
  2921.                                     }
  2922.                                     
  2923.                                 // if we have an error, we try again, otherwise we go to the page
  2924.                                 if (hit == 0)
  2925.                                     {
  2926.                                     SysBeep(1);
  2927.                                     NumToString(tempLong, theString);
  2928.                                     SetDialogItemText(theHandle, theString);
  2929.                                     SelectDialogItemText(dPtr, 4, 0, 32767);
  2930.                                     }
  2931.                                 else
  2932.                                     {
  2933.                                     ((GXDataPtr)pData)->currentPage = tempLong;
  2934.                                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2935.                                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2936.                                     }
  2937.                                 }
  2938.                             } while ((hit != ok) && (hit != cancel));
  2939.                             
  2940.                         DisposeDialog(dPtr);
  2941.                         EndMovableModal();
  2942.                         }
  2943.                         
  2944.                     }
  2945.                     break;
  2946.                     
  2947.                 }
  2948.             if (anErr == noErr)
  2949.                 anErr = eActionAlreadyHandled;
  2950.             break;
  2951.         
  2952.         }
  2953.     
  2954.     return(anErr);
  2955.     
  2956. } // GXCommand
  2957.  
  2958. // --------------------------------------------------------------------------------------------------------------
  2959. static OSErr    GXFilePrintPage(WindowPtr pWindow, WindowDataPtr pData,
  2960.                     Rect * pageRect, long *pageNum)
  2961. {
  2962. #pragma unused (pWindow, pageRect)
  2963.  
  2964.     OSErr        anErr = noErr;
  2965.     gxShape     thisShape;
  2966.     gxFormat     thisFormat;
  2967.     
  2968.     GXReadPrintFilePage(((GXDataPtr)pData)->thePrintFile, *pageNum, 0, nil, &thisFormat, &thisShape);
  2969.     anErr = GXGetJobError(pData->hPrint);
  2970.     nrequire(anErr, ReadPrintFilePage);
  2971.  
  2972.     GXPrintPage(pData->hPrint, *pageNum, thisFormat, thisShape);
  2973.     anErr = GXGetJobError(pData->hPrint);
  2974.     nrequire(anErr, PrintPage);
  2975.  
  2976.     GXDisposeFormat(thisFormat);
  2977.     GXDisposeShape(thisShape);
  2978.  
  2979. // FALL THROUGH EXCEPTION HANDLING
  2980. PrintPage:
  2981. ReadPrintFilePage:
  2982.     // tell it to stop printing when we reach the end
  2983.     if (*pageNum >= ((GXDataPtr)pData)->numberOfPages)
  2984.         *pageNum = -1;
  2985.     
  2986.     return(anErr);
  2987.     
  2988. } // GXFilePrintPage
  2989.  
  2990. // --------------------------------------------------------------------------------------------------------------
  2991.  
  2992. OSErr    GXGetDocumentRect(WindowPtr pWindow, WindowDataPtr pData, 
  2993.             LongRect * documentRectangle, Boolean forGrow)
  2994. {
  2995. #pragma unused (pWindow, forGrow)
  2996.  
  2997.     gxRectangle        pageSize, paperSize;
  2998.     
  2999.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  3000.  
  3001.     documentRectangle->left = 0;
  3002.     documentRectangle->top = 0;
  3003.     documentRectangle->bottom = FixedMultiply(paperSize.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor) >> 16;
  3004.     documentRectangle->right = FixedMultiply(paperSize.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor) >> 16;
  3005.         
  3006.     return(noErr);
  3007.     
  3008. } // GXGetDocumentRect
  3009.  
  3010. // --------------------------------------------------------------------------------------------------------------
  3011.  
  3012. static long GXCalculateIdleTime(WindowPtr pWindow, WindowDataPtr pData)
  3013. {
  3014. #pragma unused (pWindow)
  3015.  
  3016.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle))
  3017.         return(0);
  3018.     else
  3019.         return(kMaxWaitTime);
  3020.         
  3021. } // GXCalculateIdleTime
  3022.  
  3023. // --------------------------------------------------------------------------------------------------------------
  3024.  
  3025. static Boolean    GXFilterEvent(WindowPtr pWindow, WindowDataPtr pData, EventRecord *pEvent)
  3026. {
  3027.     if     (
  3028.         (!gMachineInfo.amInBackground) &&
  3029.         (pEvent->what == nullEvent) &&
  3030.         (pWindow == FrontWindow()) &&
  3031.         (EmptyRgn( ((WindowPeek)pWindow)->updateRgn)) &&
  3032.         (MOVESELECTION(pEvent->when) )
  3033.         )
  3034.         {
  3035.         // erase the old
  3036.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  3037.         
  3038.         // draw the new, moving onto the next pattern
  3039.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  3040.         }
  3041.         
  3042.     return(false);
  3043.     
  3044. } // GXFilterEvent
  3045.  
  3046. // --------------------------------------------------------------------------------------------------------------
  3047.  
  3048. static OSErr    GXDragAddFlavors(WindowPtr pWindow, WindowDataPtr pData, DragReference theDragRef)
  3049. {
  3050. #pragma unused (pWindow)
  3051.  
  3052.     OSErr    anErr = noErr;
  3053.     
  3054.     SetDragSendProc(theDragRef, gGXSendDataProc, pData);
  3055.     AddDragItemFlavor(theDragRef, 1, 'qdgx', nil, 0, 0);
  3056.     AddDragItemFlavor(theDragRef, 1, 'PICT', nil, 0, 0);
  3057.     
  3058.     return(anErr);
  3059.     
  3060. } // GXDragAddFlavors
  3061.  
  3062. // --------------------------------------------------------------------------------------------------------------
  3063.  
  3064. static OSErr    GXAdjustCursor(WindowPtr pWindow, WindowDataPtr pData, Point * localMouse, RgnHandle globalRgn)
  3065. {
  3066. #pragma unused (pWindow)
  3067.  
  3068.     OSErr        anErr = noErr;
  3069.     Handle        theCursor;
  3070.     Rect        selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  3071.     Rect        globalSelection;
  3072.     
  3073.     OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  3074.     
  3075.     globalSelection = selectionRect;
  3076.     LocalToGlobal(&TopLeft(globalSelection));
  3077.     LocalToGlobal(&BotRight(globalSelection));
  3078.     
  3079.     if (!PtInRect(*localMouse, &selectionRect) )
  3080.         {
  3081.         short    cursorID;
  3082.         Boolean    colorCursor;
  3083.         
  3084.         cursorID = ((GXDataPtr)pData)->contentClickMode;
  3085.         if (cursorID == kSelectionTool)
  3086.             {
  3087.             colorCursor = false;
  3088.             cursorID = crossCursor;
  3089.             }
  3090.         else
  3091.             {
  3092.             colorCursor = true;
  3093.             cursorID += kIconBase;
  3094.             }
  3095.             
  3096.         if (colorCursor)
  3097.             theCursor = (Handle)GetCCursor(cursorID);
  3098.         else
  3099.             theCursor = (Handle)GetCursor(cursorID);
  3100.         if (theCursor)
  3101.             {
  3102.             if (colorCursor)
  3103.                 {
  3104.                 SetCCursor((CCrsrHandle)theCursor);
  3105.                 DisposeCCursor((CCrsrHandle)theCursor);
  3106.                 }
  3107.             else
  3108.                 {
  3109.                 char    oldState;
  3110.                 
  3111.                 oldState = HGetState(theCursor);
  3112.                 HLock((Handle) theCursor);
  3113.                 SetCursor(*(CursHandle)theCursor);
  3114.                 HSetState(theCursor, oldState);
  3115.                 }
  3116.             anErr = eActionAlreadyHandled;
  3117.             }
  3118.     
  3119.         // make sure we get mouse-moved events if the mouse moves into the selection rect,
  3120.         // so that we can change the cursor
  3121.         if (!EmptyRect(&globalSelection))
  3122.             {    
  3123.             RgnHandle    tempRgn = NewRgn();
  3124.             
  3125.             RectRgn(tempRgn, &globalSelection);
  3126.             DiffRgn(globalRgn, tempRgn, globalRgn);
  3127.             DisposeRgn(tempRgn);
  3128.             }
  3129.         }
  3130.     else
  3131.         {
  3132.         // if we're already in the selection rect, we don't need mouse-moved events as long
  3133.         // as we stay there
  3134.         RectRgn(globalRgn, &globalSelection);
  3135.         }
  3136.     
  3137.     return(anErr);
  3138.     
  3139. } // GXAdjustCursor
  3140.  
  3141. // --------------------------------------------------------------------------------------------------------------
  3142.  
  3143. static OSErr    GXMakeWindow(WindowPtr pWindow, WindowDataPtr pData)
  3144. {
  3145.     OSErr                anErr = noErr;
  3146.     
  3147.     pData->pCloseWindow         = (CloseWindowProc)            GXCloseWindow;
  3148.     pData->pAdjustMenus         = (AdjustMenusProc)            GXAdjustMenus;
  3149.     pData->pCommand                = (CommandProc)                GXCommand;
  3150.     pData->pUpdateWindow         = (UpdateWindowProc)        GXUpdateWindow;
  3151.     pData->pContentClick         = (ContentClickProc)        GXContentClick;
  3152.     pData->pGetDocumentRect     = (GetDocumentRectProc)        GXGetDocumentRect;
  3153.     pData->pPrintPage             = (PrintPageProc)            GXFilePrintPage;
  3154.     pData->pFilterEvent             = (FilterEventProc)            GXFilterEvent;
  3155.     pData->pCalculateIdleTime    = (CalculateIdleTimeProc)    GXCalculateIdleTime;
  3156.     pData->pAdjustCursor        = (AdjustCursorProc)        GXAdjustCursor;
  3157.     pData->pDragAddFlavors        = (DragAddFlavorsProc)        GXDragAddFlavors;
  3158.     
  3159.     pData->documentOutputsGX    = true;
  3160.     pData->hasGrow                = true;
  3161.     pData->minHSize                = kMinGXDocSize + kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3162.     pData->hScrollAmount        = 10;
  3163.     pData->vScrollAmount        = 10;
  3164.     pData->hScrollOffset        = kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3165.     
  3166.     // default the job info, which we need to have
  3167.     anErr = DoDefault(pData);
  3168.     nrequire(anErr, DoDefault);
  3169.  
  3170.     ((GXDataPtr)pData)->thePrintFile = GXOpenPrintFile(pData->hPrint, &pData->fileSpec, fsRdWrPerm);
  3171.     anErr = GXGetJobError(pData->hPrint);
  3172.     nrequire(anErr, OpenPrintFile);
  3173.  
  3174.     /*
  3175.      *    The assumption here is that the GXOpenPrintFile leaves the resfile on top.
  3176.      *    We need this refnum so that any resource handles the translator gets will
  3177.      *    match those that GXOpenPrintFile used for calls to GXNewFont.  See the call
  3178.      *    to GXDrawShape in GXUpdateWindow
  3179.      */
  3180.     ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  3181.  
  3182.     // close down other paths to the file -- because we don't need them
  3183.     if (pData->resRefNum != -1)
  3184.         {
  3185.         CloseResFile(pData->resRefNum);
  3186.         pData->resRefNum = -1;
  3187.         }
  3188.     if (pData->dataRefNum != -1)
  3189.         {
  3190.         FSClose(pData->dataRefNum);
  3191.         pData->dataRefNum = -1;
  3192.         }
  3193.         
  3194.     // default to normal printing -- so if the user prints, we go to normal mode at first
  3195.     {
  3196.     Collection    jobCollection = GXGetJobCollection(pData->hPrint);
  3197.     gxJobInfo    theInfo;
  3198.     long        theSize = sizeof(theInfo);
  3199.     
  3200.     if (GetCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, &theSize, &theInfo) == noErr)
  3201.         {
  3202.         theInfo.priority = gxPrintJobASAP;
  3203.         AddCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, theSize, &theInfo);
  3204.         }
  3205.     
  3206.     }
  3207.     
  3208.     // by default we have no pages
  3209.     ((GXDataPtr)pData)->numberOfPages        = GXCountPrintFilePages(((GXDataPtr)pData)->thePrintFile);
  3210.     ((GXDataPtr)pData)->currentPage            = 1;
  3211.     ((GXDataPtr)pData)->zoomFactor            = ff(1);
  3212.     ((GXDataPtr)pData)->contentClickMode    = kSelectionTool;
  3213.     anErr = GXGetJobError(pData->hPrint);
  3214.     if ( (anErr == noErr) && (((GXDataPtr)pData)->numberOfPages == 0) )
  3215.         anErr = eDocumentContainsNoPages;
  3216.     nrequire(anErr, GXCountPrintFilePages);
  3217.     
  3218.     if (((GXDataPtr)pData)->numberOfPages > 1)
  3219.         pData->hScrollOffset += kPageControlsWidth;
  3220.         
  3221.     ((GXDataPtr)pData)->pageAnnotations = (gxShape**) NewHandleClear( (((GXDataPtr)pData)->numberOfPages * sizeof(gxShape)) );
  3222.     anErr = MemError();
  3223.     if (anErr == noErr)
  3224.         anErr = LoadOrSaveAnnotations(pData, kLoadAnnotations);
  3225.     nrequire(anErr, FailedToAllocateAnnotation);
  3226.     
  3227.     // set up so we can draw inside of this window
  3228.     ((GXDataPtr)pData)->parentViewPort = GXNewWindowViewPort((WindowPtr)pWindow);
  3229.     ((GXDataPtr)pData)->childViewPort = GXNewViewPort(gxScreenViewDevices);
  3230.     GXSetViewPortParent(((GXDataPtr)pData)->childViewPort, ((GXDataPtr)pData)->parentViewPort);
  3231.     GXSetViewPortAttributes(((GXDataPtr)pData)->childViewPort, gxAlwaysGridPort);
  3232.     GXSetViewPortDither(((GXDataPtr)pData)->childViewPort, 4);
  3233.     
  3234.     // fetch the current page
  3235.     anErr = GetCurrentPage((GXDataPtr) pData, true);
  3236.     nrequire(anErr, GetCurrentPage);
  3237.     
  3238.     // if this document contains PostScript do a warning
  3239.     {
  3240.     gxTranslatedDocumentInfo theInfo;
  3241.     long theSize = sizeof(theInfo);
  3242.     
  3243.     if     (
  3244.         (GetCollectionItem(GXGetJobCollection(pData->hPrint),
  3245.                             gxTranslatedDocumentTag,
  3246.                             gxPrintingTagID,
  3247.                             &theSize,
  3248.                             &theInfo
  3249.                             ) == noErr) &&
  3250.         (theInfo.translatorInfo & gxContainsPostScript)
  3251.         )
  3252.         ConductErrorDialog(eDocumentContainsPS, cOpen, ok);
  3253.     }
  3254.     
  3255.     return(anErr);
  3256.     
  3257. // EXCEPTION HANDLING
  3258. GetCurrentPage:
  3259. FailedToAllocateAnnotation:
  3260. GXCountPrintFilePages:
  3261.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  3262.     
  3263. OpenPrintFile:
  3264.     GXDisposeJob(pData->hPrint);
  3265.         
  3266. DoDefault:
  3267.     return(anErr);
  3268.     
  3269. } // GXMakeWindow
  3270.  
  3271.  
  3272. // --------------------------------------------------------------------------------------------------------------
  3273.  
  3274. OSErr    GXPreflightWindow(PreflightPtr pPreflightData)
  3275. {    
  3276.     pPreflightData->continueWithOpen     = true;
  3277.     pPreflightData->wantVScroll            = true;
  3278.     pPreflightData->wantHScroll            = true;
  3279.     pPreflightData->doZoom                = true;
  3280.     pPreflightData->makeProcPtr         = GXMakeWindow;
  3281.     pPreflightData->storageSize         = sizeof(GXDataRecord);
  3282.     
  3283.     return(noErr);
  3284.     
  3285. } // GXPreflightWindow
  3286.  
  3287. // --------------------------------------------------------------------------------------------------------------
  3288.  
  3289. void GXGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes)
  3290. {
  3291.     if (gMachineInfo.haveGXPrinting)
  3292.         {
  3293.         pFileTypes[*numTypes]         = 'sjob';
  3294.         pDocumentTypes[*numTypes]     = kGXWindow;
  3295.         (*numTypes)++;
  3296.  
  3297.         pFileTypes[*numTypes]         = 'tjob';
  3298.         pDocumentTypes[*numTypes]     = kGXWindow;
  3299.         (*numTypes)++;
  3300.  
  3301.         pFileTypes[*numTypes]         = 'rjob';
  3302.         pDocumentTypes[*numTypes]     = kGXWindow;
  3303.         (*numTypes)++;
  3304.  
  3305.         pFileTypes[*numTypes]         = 'qjob';
  3306.         pDocumentTypes[*numTypes]     = kGXWindow;
  3307.         (*numTypes)++;
  3308.         }
  3309.         
  3310. } // GXGetFileTypes
  3311.